<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Models\AcademicInfo;
use App\Models\Admission;
use App\Models\Attachment;
use App\Models\Dependent;
use Core\Controller;
use Core\Csrf;
use Core\Session;
use Core\Upload;
use Core\Validator;
use Core\View;
use Dompdf\Dompdf;
use Dompdf\Options;

final class AdminAdmissionController extends Controller
{
    public function index(): void
    {
        $this->requireAdmin();
        $config = require dirname(__DIR__, 2) . '/config/app.php';
        $filters = [
            'search' => trim((string)($_GET['search'] ?? '')),
            'status' => trim((string)($_GET['status'] ?? '')),
            'date_from' => trim((string)($_GET['date_from'] ?? '')),
            'date_to' => trim((string)($_GET['date_to'] ?? '')),
        ];
        $this->view('admin/admissions/index', [
            'config' => $config,
            'filters' => $filters,
            'admissions' => Admission::search($filters),
            'success' => Session::getFlash('success'),
            'error' => Session::getFlash('error'),
            'adminUser' => \App\Models\AdminUser::current(),
        ], 'admin');
    }

    public function show(string $id): void
    {
        $this->requireAdmin();
        $admission = Admission::findWithRelations((int)$id);
        if (!$admission) { http_response_code(404); exit('Ficha não encontrada.'); }
        $config = require dirname(__DIR__, 2) . '/config/app.php';
        $this->view('admin/admissions/show', [
            'admission' => $admission,
            'config' => $config,
            'success' => Session::getFlash('success'),
            'error' => Session::getFlash('error'),
            'adminUser' => \App\Models\AdminUser::current(),
        ], 'admin');
    }

    public function edit(string $id): void
    {
        $this->requireAdmin();
        $admission = Admission::findWithRelations((int)$id);
        if (!$admission) { http_response_code(404); exit('Ficha não encontrada.'); }

        $errors = Session::errors();
        if (empty($errors)) {
            Session::forget('_old_input');
        }

        $config = require dirname(__DIR__, 2) . '/config/app.php';
        $this->view('admin/admissions/edit', [
            'admission' => $admission,
            'config' => $config,
            'errors' => $errors,
            'error' => Session::getFlash('error'),
            'adminUser' => \App\Models\AdminUser::current(),
        ], 'admin');
    }

    public function updateStatus(string $id): void
    {
        $this->requireAdmin();

        if (!Csrf::verify($_POST['_token'] ?? null)) {
            http_response_code(419);
            exit('Token CSRF inválido.');
        }

        $admissionId = (int) $id;
        $admission = Admission::find($admissionId);

        if (!$admission) {
            http_response_code(404);
            exit('Ficha não encontrada.');
        }

        $config = require dirname(__DIR__, 2) . '/config/app.php';
        $status = trim((string) ($_POST['status'] ?? ''));

        if (!array_key_exists($status, $config['statuses'])) {
            Session::flash('error', 'Status inválido para esta ficha.');
            $this->redirectTo('admin/admissoes/' . $admissionId);
        }

        Admission::updateStatus($admissionId, $status);

        Session::flash('success', 'Status do colaborador atualizado com sucesso.');
        $this->redirectTo('admin/admissoes/' . $admissionId);
    }

    public function confirmDestroy(string $id): void
    {
        $this->requireAdmin();

        $admission = Admission::find((int) $id);

        if (!$admission) {
            http_response_code(404);
            exit('Ficha não encontrada.');
        }

        $this->view('admin/admissions/delete', [
            'admission' => $admission,
            'success' => Session::getFlash('success'),
            'error' => Session::getFlash('error'),
            'adminUser' => \App\Models\AdminUser::current(),
        ], 'admin');
    }

    public function destroy(string $id): void
    {
        $this->requireAdmin();

        if (!Csrf::verify($_POST['_token'] ?? null)) {
            Session::flash('error', 'Token CSRF inválido. Atualizamos a confirmação; tente novamente.');
            $this->redirectTo('admin/admissoes/' . (int) $id . '/excluir');
        }

        $admissionId = (int) $id;
        $admission = Admission::find($admissionId);

        if (!$admission) {
            http_response_code(404);
            exit('Ficha não encontrada.');
        }

        $attachments = Attachment::forAdmission($admissionId);

        Admission::delete($admissionId);

        foreach ($attachments as $attachment) {
            $absolutePath = dirname(__DIR__, 2) . '/storage/' . ltrim((string) ($attachment['relative_path'] ?? ''), '/');

            if ($absolutePath !== dirname(__DIR__, 2) . '/storage/' && is_file($absolutePath)) {
                @unlink($absolutePath);
            }
        }

        Session::flash('success', 'Resposta excluída com sucesso.');
        $this->redirectTo('admin/admissoes');
    }

   public function update(string $id): void
{
    $this->requireAdmin();

    if (!Csrf::verify($_POST['_token'] ?? null)) {
        http_response_code(419);
        exit('Token CSRF inválido.');
    }

    $admissionId = (int) $id;

    if (!Admission::find($admissionId)) {
        http_response_code(404);
        exit('Ficha não encontrada.');
    }

    $errors = Validator::admission($_POST, $_FILES, true);
    $allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf'];

    foreach (['profile_photo', 'rg_front', 'rg_back', 'cref_document', 'mei_certificate', 'marriage_certificate', 'divorce_annotation', 'work_card'] as $field) {
        if (isset($_FILES[$field]) && ($_FILES[$field]['error'] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_NO_FILE) {
            $fileError = Validator::file($_FILES[$field], $allowedMimeTypes, 5);
            if ($fileError) {
                $errors[$field] = $fileError;
            }
        }
    }

    $cpf = preg_replace('/\D/', '', (string) ($_POST['cpf'] ?? ''));

    if (Admission::existsByCpfExcept($cpf, $admissionId)) {
        $errors['cpf'] = 'Já existe outra ficha cadastrada com este CPF.';
    }

    if (!empty($errors)) {
        Session::putErrors($errors);
        Session::putOldInput($_POST);
        $this->redirectTo('admin/admissoes/' . $admissionId . '/editar');
    }

    try {
        Admission::update($admissionId, [
            'race' => $_POST['race'],
            'unit_name' => $_POST['unit_name'],
            'job_title' => $_POST['job_title'],
            'full_name' => $_POST['full_name'],
            'father_name' => $_POST['father_name'] ?? null,
            'mother_name' => $_POST['mother_name'],
            'birth_date' => $_POST['birth_date'],
            'marital_status' => $_POST['marital_status'],
            'is_student' => (int) ($_POST['is_student'] ?? 0),
            'education_level' => $_POST['education_level'],
            'nationality' => $_POST['nationality'],
            'place_of_birth' => $_POST['place_of_birth'] ?? null,
            'personal_email' => $_POST['personal_email'],
            'phone' => preg_replace('/\D/', '', (string) $_POST['phone']),
            'emergency_contact' => preg_replace('/\D/', '', (string) $_POST['emergency_contact']),
            'address_line' => $_POST['address_line'],
            'address_number' => $_POST['address_number'],
            'neighborhood' => $_POST['neighborhood'],
            'zip_code' => preg_replace('/\D/', '', (string) $_POST['zip_code']),
            'city' => $_POST['city'],
            'address_extra' => $_POST['address_extra'] ?? null,
            'state' => strtoupper($_POST['state']),
            'rg_number' => preg_replace('/\D/', '', (string) $_POST['rg_number']),
            'rg_issue_date' => $_POST['rg_issue_date'],
            'rg_issuer' => $_POST['rg_issuer'],
            'birth_city' => $_POST['birth_city'],
            'birth_state' => strtoupper($_POST['birth_state'] ?? $_POST['state']),
            'cpf' => $cpf,
            'pis_number' => preg_replace('/\D/', '', (string) $_POST['pis_number']),
            'pis_issue_date' => $_POST['pis_issue_date'],
            'has_dependents' => (int) ($_POST['has_dependents'] ?? 0),
            'dependent_has_disability' => (int) ($_POST['dependent_has_disability'] ?? 0),
            'uses_transport_voucher' => (int) ($_POST['uses_transport_voucher'] ?? 0),
            'transport_voucher_daily_value' => (int) ($_POST['uses_transport_voucher'] ?? 0) === 1
                ? str_replace(',', '.', $_POST['transport_voucher_daily_value'] ?? '')
                : null,
            'uniform_size' => $_POST['uniform_size'] ?? null,
            'cref_number' => trim((string) ($_POST['cref_number'] ?? '')) !== '' ? trim((string) $_POST['cref_number']) : null,
            'professor_mei_cnpj' => trim((string) ($_POST['professor_mei_cnpj'] ?? '')) !== '' ? preg_replace('/\D/', '', (string) $_POST['professor_mei_cnpj']) : null,
            'employment_function' => trim((string) ($_POST['employment_function'] ?? '')) !== '' ? trim((string) $_POST['employment_function']) : null,
            'admission_date' => trim((string) ($_POST['admission_date'] ?? '')) !== '' ? $_POST['admission_date'] : null,
            'dismissal_date' => trim((string) ($_POST['dismissal_date'] ?? '')) !== '' ? $_POST['dismissal_date'] : null,
            'workload_hours' => trim((string) ($_POST['workload_hours'] ?? '')) !== '' ? trim((string) $_POST['workload_hours']) : null,
            'salary_amount' => trim((string) ($_POST['salary_amount'] ?? '')) !== ''
                ? str_replace(',', '.', $_POST['salary_amount'])
                : null,
            'salary_type' => trim((string) ($_POST['salary_type'] ?? '')) !== '' ? $_POST['salary_type'] : null,
            'bank_agency' => trim((string) ($_POST['bank_agency'] ?? '')) !== '' ? trim((string) $_POST['bank_agency']) : null,
            'bank_account' => trim((string) ($_POST['bank_account'] ?? '')) !== '' ? trim((string) $_POST['bank_account']) : null,
            'status' => $_POST['status'],
            'internal_notes' => $_POST['internal_notes'] ?? null,
        ]);
    } catch (\PDOException $e) {
        if (($e->errorInfo[1] ?? null) === 1062) {
            $errors['cpf'] = 'Já existe outra ficha cadastrada com este CPF.';
            Session::putErrors($errors);
            Session::putOldInput($_POST);
            $this->redirectTo('admin/admissoes/' . $admissionId . '/editar');
        }

        throw $e;
    }

    Dependent::replaceForAdmission(
        $admissionId,
        (int) ($_POST['has_dependents'] ?? 0) === 1 ? ($_POST['dependents'] ?? []) : []
    );

    AcademicInfo::replaceForAdmission(
        $admissionId,
        (int) ($_POST['is_student'] ?? 0) === 1 ? ($_POST['academic'] ?? null) : null
    );

    foreach (['profile_photo', 'rg_front', 'rg_back', 'cref_document', 'mei_certificate', 'marriage_certificate', 'divorce_annotation', 'work_card'] as $field) {
        if (
            !isset($_FILES[$field]) ||
            (int) ($_FILES[$field]['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE
        ) {
            continue;
        }

        try {
            Attachment::upsert(
                $admissionId,
                $field,
                Upload::store($_FILES[$field], 'uploads/admissions', $allowedMimeTypes, 5)
            );
        } catch (\RuntimeException $e) {
            $errors[$field] = $e->getMessage();
            Session::flash('error', 'Revise o formulário. Houve problema no envio dos anexos.');
            Session::putErrors($errors);
            Session::putOldInput($_POST);
            $this->redirectTo('admin/admissoes/' . $admissionId . '/editar');
        }
    }

    if ((int) ($_POST['has_dependents'] ?? 0) === 1 && isset($_FILES['dependent_birth_certificates'])) {
        foreach (array_keys($_POST['dependents'] ?? []) as $index) {
            $file = $this->extractNestedUpload($_FILES['dependent_birth_certificates'], (int) $index);
            if (!$file || (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
                continue;
            }

            try {
                Attachment::upsert(
                    $admissionId,
                    'dependent_birth_certificate_' . (int) $index,
                    Upload::store($file, 'uploads/admissions', $allowedMimeTypes, 5)
                );
            } catch (\RuntimeException $e) {
                $errors["dependent_birth_certificates.$index"] = $e->getMessage();
                Session::flash('error', 'Revise o formulário. Houve problema no envio dos anexos.');
                Session::putErrors($errors);
                Session::putOldInput($_POST);
                $this->redirectTo('admin/admissoes/' . $admissionId . '/editar');
            }
        }
    }

    Session::forget('_old_input');
    Session::forget('_errors');
    Session::flash('success', 'Ficha atualizada com sucesso.');
    $this->redirectTo('admin/admissoes/' . $admissionId);
}


    private function extractNestedUpload(array $filesField, int $index): ?array
    {
        if (!isset($filesField['name'][$index])) {
            return null;
        }

        return [
            'name' => $filesField['name'][$index] ?? '',
            'type' => $filesField['type'][$index] ?? '',
            'tmp_name' => $filesField['tmp_name'][$index] ?? '',
            'error' => $filesField['error'][$index] ?? UPLOAD_ERR_NO_FILE,
            'size' => $filesField['size'][$index] ?? 0,
        ];
    }

    public function print(string $id): void
    {
        $this->requireAdmin();
        $admission = Admission::findWithRelations((int)$id);
        if (!$admission) { http_response_code(404); exit('Ficha não encontrada.'); }
        $config = require dirname(__DIR__, 2) . '/config/app.php';
        View::render('admin/admissions/print', ['admission' => $admission, 'config' => $config], 'print');
    }

    public function pdf(string $id): void
    {
        $this->requireAdmin();
        if (!class_exists(Dompdf::class)) {
            Session::flash('error', 'Dompdf não instalado. Rode composer install para habilitar PDF.');
            $this->redirectTo('admin/admissoes/' . (int)$id);
        }
        $admission = Admission::findWithRelations((int)$id);
        if (!$admission) { http_response_code(404); exit('Ficha não encontrada.'); }
        $config = require dirname(__DIR__, 2) . '/config/app.php';
        $html = View::renderToString('admin/admissions/pdf', ['admission' => $admission, 'config' => $config]);
        $options = new Options();
        $options->set('isRemoteEnabled', true);
        $dompdf = new Dompdf($options);
        $dompdf->loadHtml($html, 'UTF-8');
        $dompdf->setPaper('A4');
        $dompdf->render();
        $dompdf->stream('ficha-admissao-' . $admission['id'] . '.pdf', ['Attachment' => false]);
        exit;
    }

    public function previewAttachment(string $id, string $attachmentId): void
    {
        $this->requireAdmin();

        $admission = Admission::find((int) $id);
        $attachment = Attachment::find((int) $attachmentId);

        if (
            !$admission ||
            !$attachment ||
            (int) $attachment['admission_id'] !== (int) $admission['id']
        ) {
            http_response_code(404);
            exit('Anexo não encontrado.');
        }

        $absolutePath = dirname(__DIR__, 2) . '/storage/' . $attachment['relative_path'];

        if (!file_exists($absolutePath)) {
            http_response_code(404);
            exit('Arquivo físico não encontrado.');
        }

        header('Content-Type: ' . $attachment['mime_type']);
        header('Content-Length: ' . filesize($absolutePath));
        header('Content-Disposition: inline; filename="' . basename($attachment['original_name']) . '"');

        readfile($absolutePath);
        exit;
    }

    public function downloadAttachment(string $id, string $attachmentId): void
    {
        $this->requireAdmin();
        $admission = Admission::find((int)$id);
        $attachment = Attachment::find((int)$attachmentId);
        if (!$admission || !$attachment || (int)$attachment['admission_id'] !== (int)$admission['id']) { http_response_code(404); exit('Anexo não encontrado.'); }
        $absolutePath = dirname(__DIR__, 2) . '/storage/' . $attachment['relative_path'];
        if (!file_exists($absolutePath)) { http_response_code(404); exit('Arquivo físico não encontrado.'); }
        header('Content-Description: File Transfer');
        header('Content-Type: ' . $attachment['mime_type']);
        header('Content-Disposition: attachment; filename="' . basename($attachment['original_name']) . '"');
        header('Content-Length: ' . filesize($absolutePath));
        readfile($absolutePath);
        exit;
    }
}
