<?php
namespace Modules\Tecnicos\Controllers;

use PDO;
use Exception;

class TecnicosController
{
    private PDO $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    private function json($data, int $status = 200)
    {
        http_response_code($status);
        header('Content-Type: application/json');
        echo json_encode(['data' => $data]);
    }

    private function error($message, int $status = 422, array $details = [])
    {
        http_response_code($status);
        header('Content-Type: application/json');
        echo json_encode(['error' => ['message' => $message, 'details' => $details]]);
    }

    private function getInput(): array
    {
        $raw = file_get_contents('php://input');
        $data = json_decode($raw, true);
        return is_array($data) ? $data : [];
    }

    // CRUD
    public function list()
    {
        $q = isset($_GET['q']) ? trim((string)$_GET['q']) : '';
        $page = max(1, (int)($_GET['page'] ?? 1));
        $limit = max(1, min(100, (int)($_GET['limit'] ?? 20)));
        $offset = ($page - 1) * $limit;
        $where = '';
        $params = [];
        if ($q !== '') {
            $where = 'WHERE nome LIKE :q OR cpf LIKE :q OR email LIKE :q';
            $params[':q'] = '%' . $q . '%';
        }
        $stmt = $this->db->prepare("SELECT * FROM technicians $where ORDER BY id DESC LIMIT :limit OFFSET :offset");
        foreach ($params as $k => $v) { $stmt->bindValue($k, $v); }
        $stmt->bindValue(':limit', $limit, PDO::PARAM_INT);
        $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
        $stmt->execute();
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $this->json(['page'=>$page,'limit'=>$limit,'data'=>$rows]);
    }

    public function getById($id)
    {
        $stmt = $this->db->prepare('SELECT * FROM technicians WHERE id = :id');
        $stmt->execute([':id' => (int)$id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row) return $this->error('Técnico não encontrado', 404);
        $this->json($row);
    }

    private function validate(array $p, bool $isUpdate = false): array
    {
        $errs = [];
        $nome = trim((string)($p['nome'] ?? ''));
        $cpf = trim((string)($p['cpf'] ?? ''));
        $rg = trim((string)($p['rg'] ?? ''));
        $telefone = trim((string)($p['telefone'] ?? ''));
        $email = trim((string)($p['email'] ?? ''));
        $comissao = isset($p['comissao_percent']) ? (float)$p['comissao_percent'] : null;

        if ($nome === '') $errs[] = 'Nome é obrigatório';
        if ($cpf === '') $errs[] = 'CPF é obrigatório';
        if ($cpf !== '') {
            $d = preg_replace('/\D/', '', $cpf);
            if (strlen($d) !== 11) $errs[] = 'CPF deve conter 11 dígitos';
        }
        if ($rg === '') $errs[] = 'RG é obrigatório';
        if ($telefone === '') $errs[] = 'Telefone é obrigatório';
        if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) $errs[] = 'E-mail inválido';
        if ($comissao !== null && ($comissao < 0 || $comissao > 100)) $errs[] = 'Comissão deve estar entre 0 e 100';

        // Unique by CPF
        if ($cpf !== '') {
            $stmt = $this->db->prepare('SELECT id FROM technicians WHERE cpf = :cpf');
            $stmt->execute([':cpf' => $cpf]);
            $exist = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($exist) {
                if ($isUpdate) {
                    // allow updating same record
                    if ((int)$exist['id'] !== (int)($p['id'] ?? 0)) $errs[] = 'CPF já cadastrado para outro técnico';
                } else {
                    $errs[] = 'CPF já cadastrado';
                }
            }
        }
        return $errs;
    }

    public function create()
    {
        try {
            $p = $this->getInput();
            $errs = $this->validate($p, false);
            if ($errs) return $this->error('Falha de validação', 422, $errs);

            $sql = 'INSERT INTO technicians (nome, cpf, rg, email, telefone, bank_name, bank_agencia, bank_conta, pix_key, comissao_percent, pdv_code, enabled) VALUES (:nome,:cpf,:rg,:email,:telefone,:bank_name,:bank_agencia,:bank_conta,:pix_key,:comissao_percent,:pdv_code,:enabled)';
            $stmt = $this->db->prepare($sql);
            $stmt->execute([
                ':nome' => $p['nome'], ':cpf' => $p['cpf'], ':rg' => $p['rg'],
                ':email' => ($p['email'] ?? null), ':telefone' => $p['telefone'],
                ':bank_name' => ($p['bank_name'] ?? null), ':bank_agencia' => ($p['bank_agencia'] ?? null), ':bank_conta' => ($p['bank_conta'] ?? null), ':pix_key' => ($p['pix_key'] ?? null),
                ':comissao_percent' => isset($p['comissao_percent']) ? (float)$p['comissao_percent'] : null,
                ':pdv_code' => ($p['pdv_code'] ?? null), ':enabled' => isset($p['enabled']) ? (int)$p['enabled'] : 1,
            ]);
            $id = (int)$this->db->lastInsertId();
            return $this->getById($id);
        } catch (Exception $e) { return $this->error('Erro interno', 500, [$e->getMessage()]); }
    }

    public function update($id)
    {
        try {
            $p = $this->getInput();
            $p['id'] = (int)$id;
            $errs = $this->validate($p, true);
            if ($errs) return $this->error('Falha de validação', 422, $errs);

            $sql = 'UPDATE technicians SET nome=:nome, cpf=:cpf, rg=:rg, email=:email, telefone=:telefone, bank_name=:bank_name, bank_agencia=:bank_agencia, bank_conta=:bank_conta, pix_key=:pix_key, comissao_percent=:comissao_percent, pdv_code=:pdv_code, enabled=:enabled WHERE id=:id';
            $stmt = $this->db->prepare($sql);
            $stmt->execute([
                ':id' => (int)$id,
                ':nome' => $p['nome'], ':cpf' => $p['cpf'], ':rg' => $p['rg'],
                ':email' => ($p['email'] ?? null), ':telefone' => $p['telefone'],
                ':bank_name' => ($p['bank_name'] ?? null), ':bank_agencia' => ($p['bank_agencia'] ?? null), ':bank_conta' => ($p['bank_conta'] ?? null), ':pix_key' => ($p['pix_key'] ?? null),
                ':comissao_percent' => isset($p['comissao_percent']) ? (float)$p['comissao_percent'] : null,
                ':pdv_code' => ($p['pdv_code'] ?? null), ':enabled' => isset($p['enabled']) ? (int)$p['enabled'] : 1,
            ]);
            return $this->getById($id);
        } catch (Exception $e) { return $this->error('Erro interno', 500, [$e->getMessage()]); }
    }

    public function delete($id)
    {
        $stmt = $this->db->prepare('DELETE FROM technicians WHERE id = :id');
        $stmt->execute([':id' => (int)$id]);
        http_response_code(204);
    }

    // Relacionamentos e integrações
    public function commissions($id)
    {
        $stmt = $this->db->prepare('SELECT SUM(commission_amount) AS total_commission FROM technician_service_history WHERE technician_id = :id');
        $stmt->execute([':id' => (int)$id]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC) ?: ['total_commission' => 0];
        $this->json($row);
    }

    public function serviceHistory($id)
    {
        $stmt = $this->db->prepare('SELECT * FROM technician_service_history WHERE technician_id = :id ORDER BY service_date DESC, id DESC');
        $stmt->execute([':id' => (int)$id]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $this->json($rows);
    }

    public function identify()
    {
        $p = $this->getInput();
        $code = trim((string)($p['pdv_code'] ?? ''));
        if ($code === '') return $this->error('Código PDV obrigatório', 422);
        $stmt = $this->db->prepare('SELECT id, nome, enabled FROM technicians WHERE pdv_code = :code');
        $stmt->execute([':code' => $code]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row) return $this->error('Técnico não encontrado', 404);
        if (!(int)$row['enabled']) return $this->error('Técnico inativo', 409);
        $this->json($row);
    }

    public function reportProductivity()
    {
        $from = $_GET['from'] ?? date('Y-m-01');
        $to = $_GET['to'] ?? date('Y-m-t');
        $stmt = $this->db->prepare('SELECT t.nome, COUNT(h.id) AS services, COALESCE(SUM(h.amount),0) AS total_amount, COALESCE(SUM(h.commission_amount),0) AS total_commission FROM technicians t LEFT JOIN technician_service_history h ON h.technician_id = t.id AND h.service_date BETWEEN :from AND :to GROUP BY t.id, t.nome ORDER BY services DESC');
        $stmt->execute([':from' => $from, ':to' => $to]);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $this->json($rows);
    }

    public function exportPaymentsCsv()
    {
        $from = $_GET['from'] ?? date('Y-m-01');
        $to = $_GET['to'] ?? date('Y-m-t');
        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="pagamentos_tecnicos.csv"');
        $out = fopen('php://output', 'w');
        fputcsv($out, ['Tecnico','Serviços','Valor','Comissão']);
        $stmt = $this->db->prepare('SELECT t.nome, COUNT(h.id) AS services, COALESCE(SUM(h.amount),0) AS total_amount, COALESCE(SUM(h.commission_amount),0) AS total_commission FROM technicians t LEFT JOIN technician_service_history h ON h.technician_id = t.id AND h.service_date BETWEEN :from AND :to GROUP BY t.id, t.nome ORDER BY t.nome ASC');
        $stmt->execute([':from' => $from, ':to' => $to]);
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            fputcsv($out, [$row['nome'], $row['services'], number_format((float)$row['total_amount'], 2, '.', ''), number_format((float)$row['total_commission'], 2, '.', '')]);
        }
        fclose($out);
    }
}