<?php
declare(strict_types=1);

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../helpers/AuthHelper.php';
require_once __DIR__ . '/../models/Employees.php';

use Gabinete\Models\Employees;

class EmployeesController
{
    private Employees $employeeModel;

    public function __construct()
    {
        AuthHelper::check(); // garanta que o helper existe; senão remova esta linha
        $this->employeeModel = new Employees();
    }

    /* ========================= Rotas básicas ========================= */

    /** GET /employees */
    public function index(): void
    {
        try {
            $filters = [
                'status'        => $_GET['status']        ?? null,
                'name'          => $_GET['search']        ?? null,
                'city'          => $_GET['city']          ?? null,
                'state'         => $_GET['state']         ?? null,
                'department'    => $_GET['department']    ?? null,
                'work_location' => $_GET['work_location'] ?? null,
            ];
            $filters = array_filter($filters, fn($v) => $v !== null && $v !== '');

            $employees = !empty($filters)
                ? $this->employeeModel->search($filters)
                : $this->employeeModel->getAll();

            // View de listagem (mantive o nome que você tem usado)
            $rows = $employees;
            require __DIR__ . '/../views/employees/colaboradores.php';
        } catch (\Throwable $e) {
            $this->flash('error', 'Erro ao carregar colaboradores: ' . $e->getMessage());
            $this->redirect('/rh');
        }
    }

    /** GET /employees/create */
    public function create(): void
    {
        // Usar a nova view create_v2.php como padrão quando disponível.
        if (file_exists(__DIR__ . '/../views/employees/create_v2.php')) {
            require __DIR__ . '/../views/employees/create_v2.php';
            return;
        }

        // Fallback para a view antiga
        require __DIR__ . '/../views/employees/create.php';
    }

    /** POST /employees/store */
    public function store(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->redirect('/employees/create');
        }

        try {
            // Campos obrigatórios mínimos
            $required = ['full_name', 'cpf', 'job_title', 'salary', 'hire_date'];
            foreach ($required as $field) {
                if (empty($_POST[$field])) {
                    throw new \Exception("Campo obrigatório ausente: {$field}");
                }
            }

            // Valida CPF
            $cpf = $_POST['cpf'];
            if (!$this->employeeModel->validateCpf($cpf)) {
                throw new \Exception('CPF inválido.');
            }
            if ($this->employeeModel->cpfExists($cpf)) {
                throw new \Exception('CPF já cadastrado.');
            }

            // Upload de foto (opcional no create)
            [$photoPath, $uploadErrors] = $this->handlePhotoUpload(null, !empty($_POST['remove_photo']));
            if ($uploadErrors) {
                throw new \Exception(implode(' ', $uploadErrors));
            }

            // Monta payload para o model
            $data = [
                'full_name'     => trim((string)($_POST['full_name'] ?? '')),
                'cpf'           => $cpf,
                'rg'            => trim((string)($_POST['rg'] ?? '')),
                'birth_date'    => $_POST['birth_date']    ?? null,
                'address'       => trim((string)($_POST['address'] ?? '')),
                'city'          => trim((string)($_POST['city'] ?? '')),
                'state'         => trim((string)($_POST['state'] ?? '')),
                'postal_code'   => trim((string)($_POST['postal_code'] ?? '')),
                'phone_number'  => trim((string)($_POST['phone_number'] ?? '')),
                'job_title'     => trim((string)($_POST['job_title'] ?? '')),
                'salary'        => $this->toFloat($_POST['salary'] ?? '0'),
                'hire_date'     => $_POST['hire_date']     ?? null,
                'contract_type' => $_POST['contract_type'] ?? 'CLT',
                'cost_center'   => trim((string)($_POST['cost_center'] ?? '')),
                'department'    => trim((string)($_POST['department'] ?? '')),
                'work_location' => trim((string)($_POST['work_location'] ?? '')),
                'latitude'      => $_POST['latitude']      ?? null,
                'longitude'     => $_POST['longitude']     ?? null,
                'bank_name'     => trim((string)($_POST['bank_name'] ?? '')),
                'agency_number' => trim((string)($_POST['agency_number'] ?? '')),
                'account_number'=> trim((string)($_POST['account_number'] ?? '')),
                'status'        => $_POST['status']        ?? 'ativo',
                'photo_path'    => $photoPath,
            ];

            $newId = $this->employeeModel->create($data);
            if (!$newId) {
                throw new \Exception('Falha ao criar colaborador.');
            }

            $this->flash('success', 'Colaborador cadastrado com sucesso!');
            $this->redirect('/employees/' . (int)$newId);
        } catch (\Throwable $e) {
            $this->flash('error', $e->getMessage());
            $this->redirect('/employees/create');
        }
    }

    /** GET /employees/{id} */
    public function show(int $id): void
    {
        try {
            $employee = $this->employeeModel->findById($id);
            if (!$employee) {
                $this->flash('error', 'Colaborador não encontrado.');
                $this->redirect('/employees');
            }
            require __DIR__ . '/../views/employees/show.php';
        } catch (\Throwable $e) {
            $this->flash('error', 'Erro ao carregar colaborador: ' . $e->getMessage());
            $this->redirect('/employees');
        }
    }

    /** GET /employees/{id}/edit */
    public function edit(int $id): void
    {
        try {
            $employee = $this->employeeModel->findById($id);
            if (!$employee) {
                $this->flash('error', 'Colaborador não encontrado.');
                $this->redirect('/employees');
            }
            require __DIR__ . '/../views/employees/edit.php';
        } catch (\Throwable $e) {
            $this->flash('error', 'Erro ao carregar colaborador: ' . $e->getMessage());
            $this->redirect('/employees');
        }
    }

    /** POST /employees/{id}/update */
    public function update(int $id): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->redirect('/employees/' . (int)$id . '/edit');
        }

        try {
            $employee = $this->employeeModel->findById($id);
            if (!$employee) {
                throw new \Exception('Colaborador não encontrado.');
            }

            // Valida CPF (e duplicidade)
            $cpf = $_POST['cpf'] ?? '';
            if (!$this->employeeModel->validateCpf($cpf)) {
                throw new \Exception('CPF inválido.');
            }
            if ($this->employeeModel->cpfExists($cpf, $id)) {
                throw new \Exception('CPF já cadastrado para outro colaborador.');
            }

            // Upload/remoção de foto
            $currentPhoto = $_POST['current_photo_path'] ?? ($employee['photo_path'] ?? null);
            $removePhoto  = !empty($_POST['remove_photo']);
            [$photoPath, $uploadErrors] = $this->handlePhotoUpload($currentPhoto, $removePhoto);
            if ($uploadErrors) {
                throw new \Exception(implode(' ', $uploadErrors));
            }

            // Monta payload
            $data = [
                'full_name'     => trim((string)($_POST['full_name'] ?? '')),
                'cpf'           => $cpf,
                'rg'            => trim((string)($_POST['rg'] ?? '')),
                'birth_date'    => $_POST['birth_date']    ?? null,
                'address'       => trim((string)($_POST['address'] ?? '')),
                'city'          => trim((string)($_POST['city'] ?? '')),
                'state'         => trim((string)($_POST['state'] ?? '')),
                'postal_code'   => trim((string)($_POST['postal_code'] ?? '')),
                'phone_number'  => trim((string)($_POST['phone_number'] ?? '')),
                'job_title'     => trim((string)($_POST['job_title'] ?? '')),
                'salary'        => $this->toFloat($_POST['salary'] ?? '0'),
                'hire_date'     => $_POST['hire_date']     ?? null,
                'contract_type' => $_POST['contract_type'] ?? 'CLT',
                'cost_center'   => trim((string)($_POST['cost_center'] ?? '')),
                'department'    => trim((string)($_POST['department'] ?? '')),
                'work_location' => trim((string)($_POST['work_location'] ?? '')),
                'latitude'      => $_POST['latitude']      ?? null,
                'longitude'     => $_POST['longitude']     ?? null,
                'bank_name'     => trim((string)($_POST['bank_name'] ?? '')),
                'agency_number' => trim((string)($_POST['agency_number'] ?? '')),
                'account_number'=> trim((string)($_POST['account_number'] ?? '')),
                'status'        => $_POST['status']        ?? 'ativo',
                'photo_path'    => $photoPath, // resultado do handlePhotoUpload
            ];

            $ok = $this->employeeModel->update($id, $data);
            if (!$ok) {
                throw new \Exception('Falha ao atualizar colaborador.');
            }

            $this->flash('success', 'Alterações salvas com sucesso!');
            $this->redirect('/employees/' . (int)$id);
        } catch (\Throwable $e) {
            $this->flash('error', $e->getMessage());
            $this->redirect('/employees/' . (int)$id . '/edit');
        }
    }

    /** POST /employees/{id}/delete */
    public function destroy(int $id): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->redirect('/employees');
        }
        try {
            $employee = $this->employeeModel->findById($id);
            if (!$employee) {
                throw new \Exception('Colaborador não encontrado.');
            }

            // Se quiser remover a foto do disco ao excluir:
            if (!empty($employee['photo_path'])) {
                $this->deletePhysicalPhoto($employee['photo_path']);
            }

            if (!$this->employeeModel->delete($id)) {
                throw new \Exception('Falha ao excluir colaborador.');
            }

            $this->flash('success', 'Colaborador excluído com sucesso!');
            $this->redirect('/employees');
        } catch (\Throwable $e) {
            $this->flash('error', $e->getMessage());
            $this->redirect('/employees');
        }
    }

    /* ========================= Lote (opcional) ========================= */

    /** POST /employees/delete-multiple */
    public function deleteMultiple(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->redirect('/employees');
        }
        try {
            $ids = $_POST['employee_ids'] ?? [];
            if (empty($ids)) {
                throw new \Exception('Nenhum colaborador selecionado.');
            }
            $this->employeeModel->deleteMultiple($ids);
            $this->flash('success', count($ids) . ' colaborador(es) excluído(s).');
        } catch (\Throwable $e) {
            $this->flash('error', 'Erro ao excluir em lote: ' . $e->getMessage());
        }
        $this->redirect('/employees');
    }

    /** POST /employees/update-multiple */
    public function updateMultiple(): void
    {
        if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
            $this->redirect('/employees');
        }
        try {
            $ids = $_POST['employee_ids'] ?? [];
            if (empty($ids)) {
                throw new \Exception('Nenhum colaborador selecionado.');
            }

            $updateData = [];
            if (!empty($_POST['bulk_status']))        $updateData['status']        = $_POST['bulk_status'];
            if (!empty($_POST['bulk_department']))    $updateData['department']    = $_POST['bulk_department'];
            if (!empty($_POST['bulk_work_location'])) $updateData['work_location'] = $_POST['bulk_work_location'];
            if (empty($updateData)) {
                throw new \Exception('Nenhum campo informado para atualização em lote.');
            }

            $this->employeeModel->updateMultiple($ids, $updateData);
            $this->flash('success', count($ids) . ' colaborador(es) atualizado(s).');
        } catch (\Throwable $e) {
            $this->flash('error', 'Erro ao atualizar em lote: ' . $e->getMessage());
        }
        $this->redirect('/employees');
    }

    /* ========================= Helpers de Upload ========================= */

    /**
     * Processa upload/remoção da foto do colaborador.
     * @param string|null $currentPhotoPath caminho atual salvo no banco (ex.: "uploads/employees/abc.jpg")
     * @param bool $removePhoto se marcou para remover a foto
     * @return array [string|null $newPath, array $errors]
     */
    private function handlePhotoUpload(?string $currentPhotoPath, bool $removePhoto): array
    {
        $errors = [];
        $newPath = $currentPhotoPath;

        // Se marcou para remover e NÃO enviou nova foto
        if ($removePhoto && empty($_FILES['photo']['name'])) {
            if ($currentPhotoPath) {
                $this->deletePhysicalPhoto($currentPhotoPath);
            }
            return [null, $errors];
        }

        // Se não enviou arquivo novo, apenas mantém como está
        if (empty($_FILES['photo']['name'])) {
            return [$newPath, $errors];
        }

        $file   = $_FILES['photo'];
        $tmp    = $file['tmp_name'] ?? '';
        $size   = (int)($file['size'] ?? 0);
        $name   = $file['name'] ?? '';
        $ext    = strtolower(pathinfo($name, PATHINFO_EXTENSION));

        // validações simples
        if (!is_uploaded_file($tmp)) {
            $errors[] = 'Upload inválido.';
            return [$newPath, $errors];
        }
        if ($size > 5 * 1024 * 1024) {
            $errors[] = 'A imagem excede 5MB.';
        }
        if (!in_array($ext, ['jpg', 'jpeg', 'png', 'webp'], true)) {
            $errors[] = 'Formato inválido. Use JPG, PNG ou WEBP.';
        }
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mime  = finfo_file($finfo, $tmp);
        finfo_close($finfo);
        if (strpos((string)$mime, 'image/') !== 0) {
            $errors[] = 'Arquivo enviado não é uma imagem válida.';
        }
        if ($errors) {
            return [$newPath, $errors];
        }

        // Gera nome único
        $uuid     = bin2hex(random_bytes(10));
        $fileName = $uuid . '.' . $ext;

        // Resolve diretórios de upload (funciona com projeto com/sem /public)
        [$diskDir, $urlPrefix] = $this->getUploadsPair(); // [dir físico, prefixo URL relativo ao BASE_URL]
        if (!is_dir($diskDir)) {
            if (!@mkdir($diskDir, 0755, true) && !is_dir($diskDir)) {
                $errors[] = 'Falha ao criar diretório de upload.';
                return [$newPath, $errors];
            }
        }

        $destDisk = rtrim($diskDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName;
        if (!@move_uploaded_file($tmp, $destDisk)) {
            $errors[] = 'Falha ao mover o arquivo enviado.';
            return [$newPath, $errors];
        }

        // Remove a foto anterior (se diferente)
        if ($currentPhotoPath) {
            $this->deletePhysicalPhoto($currentPhotoPath);
        }

        // Caminho a ser salvo no banco (URL relativa sob BASE_URL)
        $newPath = rtrim($urlPrefix, '/') . '/' . $fileName;
        return [$newPath, $errors];
    }

    /** Apaga o arquivo físico se existir. */
    private function deletePhysicalPhoto(string $dbPhotoPath): void
    {
        // dbPhotoPath vem como "uploads/employees/xxx.jpg"
        [$diskDir, $urlPrefix] = $this->getUploadsPair();
        $basename = basename($dbPhotoPath);
        $candidate = rtrim($diskDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $basename;

        if (is_file($candidate)) {
            @unlink($candidate);
        } else {
            // Tenta resolver a partir da raiz do projeto também
            $projectRoot = dirname(__DIR__, 2); // .../gabinete
            $alt = $projectRoot . DIRECTORY_SEPARATOR . ltrim($dbPhotoPath, '/\\');
            if (is_file($alt)) @unlink($alt);
        }
    }

    /**
     * Retorna par [diretório físico, prefixo URL relativo] para uploads de employees.
     * - Se existir /public, grava em /public/uploads/employees e URL é "uploads/employees"
     * - Senão, grava em /uploads/employees na raiz do projeto e URL idem "uploads/employees"
     */
    private function getUploadsPair(): array
    {
        $projectRoot = dirname(__DIR__, 2); // .../gabinete
        $hasPublic   = is_dir($projectRoot . '/public');

        $diskDir   = $hasPublic
            ? $projectRoot . '/public/uploads/employees'
            : $projectRoot . '/uploads/employees';

        $urlPrefix = 'uploads/employees'; // relativo ao BASE_URL

        return [$diskDir, $urlPrefix];
    }

    /* ========================= Utils ========================= */

    private function toFloat(string $brMoney): float
    {
        // Converte "1.234,56" -> 1234.56
        $only = str_replace(['.', ' '], '', $brMoney);
        $only = str_replace(',', '.', $only);
        return is_numeric($only) ? (float)$only : 0.0;
    }

    private function flash(string $type, string $message): void
    {
        $_SESSION[$type] = $message;
    }

    private function redirect(string $path): void
    {
        // $path deve iniciar com '/', exemplo: '/employees/3'
        $url = rtrim(BASE_URL, '/') . $path;
        header('Location: ' . $url);
        exit;
    }
}
