<?php

namespace App\Controllers;

use App\Libraries\FolioService;
use App\Models\AuditLogModel;
use App\Models\ClientModel;
use App\Models\InspectionModel;
use App\Models\ReportInspectionModel;
use App\Models\ReportModel;
use App\Models\ReportPhotoModel;
use App\Models\SignatureModel;
use CodeIgniter\HTTP\RedirectResponse;
use CodeIgniter\HTTP\ResponseInterface;
use Mpdf\Mpdf;

class ReportController extends BaseController
{
    public function index(): string
    {
        $rows = (new ReportModel())
            ->select('reports.*, clients.nombre AS client_name')
            ->join('clients', 'clients.id = reports.client_id', 'left')
            ->orderBy('reports.id', 'DESC')
            ->findAll();
        return view('reports/index', [
            'title' => 'Reportes',
            'reports' => $rows,
        ]);
    }

    public function create(): string
    {
        $clients = (new ClientModel())->orderBy('nombre')->findAll();
        $inspections = (new InspectionModel())
            ->where('status', 'signed')
            ->orderBy('id', 'DESC')->findAll();

        return view('reports/create', [
            'title' => 'Nuevo reporte',
            'clients' => $clients,
            'inspections' => $inspections,
        ]);
    }

    public function store(): RedirectResponse
    {
        $clientId = (int) $this->request->getPost('client_id');
        $title = trim((string) $this->request->getPost('title'));
        $inspectionIds = array_map('intval', (array) $this->request->getPost('inspection_ids'));

        if ($clientId === 0 || $title === '') {
            return redirect()->back()->withInput()->with('error', 'Cliente y título son obligatorios.');
        }

        $data = [
            'folio' => (new FolioService())->next('report'),
            'client_id' => $clientId,
            'title' => $title,
            'pdf_template_id' => null,
            'verify_token' => FolioService::token(),
            'status' => 'draft',
            'notas' => trim((string) $this->request->getPost('notas')) ?: null,
        ];
        $id = (new ReportModel())->insert($data, true);

        $pivot = new ReportInspectionModel();
        foreach (array_values(array_filter($inspectionIds)) as $orden => $iid) {
            $pivot->insert(['report_id' => $id, 'inspection_id' => $iid, 'orden' => $orden]);
        }

        (new AuditLogModel())->record('report', (int) $id, 'create', ['folio' => $data['folio']]);
        return redirect()->to(site_url('reports/' . $id))->with('success', 'Reporte creado (folio ' . $data['folio'] . ').');
    }

    public function show(int $id): string
    {
        $report = (new ReportModel())->find($id);
        if ($report === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }
        $client = (new ClientModel())->find((int) $report['client_id']);
        $linked = (new InspectionModel())
            ->select('inspections.*')
            ->join('report_inspections', 'report_inspections.inspection_id = inspections.id')
            ->where('report_inspections.report_id', $id)
            ->orderBy('report_inspections.orden')
            ->findAll();
        $photos = (new ReportPhotoModel())->forReport($id);

        return view('reports/show', [
            'title' => 'Reporte ' . ($report['folio'] ?? '#' . $id),
            'report' => $report,
            'client' => $client,
            'inspections' => $linked,
            'photos' => $photos,
        ]);
    }

    public function edit(int $id): string
    {
        return $this->show($id);
    }

    public function update(int $id): RedirectResponse
    {
        $model = new ReportModel();
        if ($model->find($id) === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }
        $model->update($id, [
            'title' => trim((string) $this->request->getPost('title')),
            'notas' => trim((string) $this->request->getPost('notas')) ?: null,
            'status' => $this->request->getPost('status') === 'sent' ? 'sent' : 'draft',
        ]);
        (new AuditLogModel())->record('report', $id, 'update');
        return redirect()->to(site_url('reports/' . $id))->with('success', 'Reporte actualizado.');
    }

    public function delete(int $id): RedirectResponse
    {
        (new ReportModel())->delete($id);
        (new AuditLogModel())->record('report', $id, 'delete');
        return redirect()->to(site_url('reports'))->with('success', 'Reporte eliminado.');
    }

    public function uploadPhoto(int $id): RedirectResponse
    {
        if ((new ReportModel())->find($id) === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $files = $this->request->getFiles();
        $uploads = $files['photos'] ?? [];
        if (! is_array($uploads)) {
            $uploads = [$uploads];
        }

        $section = $this->normalizePhotoSection((string) $this->request->getPost('section'));
        $caption = trim((string) $this->request->getPost('caption')) ?: null;
        $dir = WRITEPATH . 'uploads/reports/' . $id;
        if (! is_dir($dir)) {
            mkdir($dir, 0775, true);
        }

        $model = new ReportPhotoModel();
        $maxOrder = (int) ($model->where('report_id', $id)->selectMax('orden')->first()['orden'] ?? 0);
        $saved = 0;

        foreach ($uploads as $file) {
            if ($file === null || ! $file->isValid()) {
                continue;
            }
            if (! str_starts_with((string) $file->getMimeType(), 'image/')) {
                continue;
            }

            $mime = $file->getMimeType();
            $size = $file->getSize();
            $name = $file->getRandomName();
            $file->move($dir, $name);
            $model->insert([
                'report_id' => $id,
                'section' => $section,
                'caption' => $caption,
                'file_path' => 'uploads/reports/' . $id . '/' . $name,
                'mime' => $mime,
                'size' => $size ?: null,
                'orden' => ++$maxOrder,
                'created_at' => date('Y-m-d H:i:s'),
            ]);
            $saved++;
        }

        if ($saved === 0) {
            return redirect()->back()->with('error', 'Selecciona al menos una imagen válida.');
        }

        (new AuditLogModel())->record('report', $id, 'upload_photos', ['count' => $saved, 'section' => $section]);
        return redirect()->to(site_url('reports/' . $id))->with('success', $saved . ' foto(s) agregada(s).');
    }

    public function deletePhoto(int $id, int $photoId): RedirectResponse
    {
        if ((new ReportModel())->find($id) === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $model = new ReportPhotoModel();
        $photo = $model->where('report_id', $id)->find($photoId);
        if ($photo !== null) {
            $path = WRITEPATH . $photo['file_path'];
            if (is_file($path)) {
                @unlink($path);
            }
            $model->delete($photoId);
            (new AuditLogModel())->record('report', $id, 'delete_photo', ['photo_id' => $photoId]);
        }

        return redirect()->to(site_url('reports/' . $id))->with('success', 'Foto eliminada.');
    }

    public function photo(int $id, int $photoId): ResponseInterface
    {
        if ((new ReportModel())->find($id) === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $photo = (new ReportPhotoModel())->where('report_id', $id)->find($photoId);
        if ($photo === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        $path = WRITEPATH . $photo['file_path'];
        if (! is_file($path)) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }

        return $this->response
            ->setHeader('Content-Type', $photo['mime'] ?: mime_content_type($path))
            ->setBody(file_get_contents($path));
    }

    public function pdf(int $id): ResponseInterface
    {
        return $this->renderPdf($id);
    }

    public function renderPdf(int $id, bool $forceDownload = false): ResponseInterface
    {
        $report = (new ReportModel())->find($id);
        if ($report === null) {
            throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
        }
        $client = (new ClientModel())->find((int) $report['client_id']);
        $inspections = (new InspectionModel())
            ->select('inspections.*')
            ->join('report_inspections', 'report_inspections.inspection_id = inspections.id')
            ->where('report_inspections.report_id', $id)
            ->orderBy('report_inspections.orden')
            ->findAll();

        $company = company_profile();
        $logoPath = company_brand_asset_path('logo');
        $verifyUrl = site_url('verify/' . $report['verify_token']);
        $clientSig = (new SignatureModel())->findFor('report', $id, 'cliente');
        $photos = (new ReportPhotoModel())->forReport($id);

        $html = view('pdf/report', [
            'report' => $report,
            'client' => $client,
            'inspections' => $inspections,
            'company' => $company,
            'logoPath' => $logoPath,
            'verifyUrl' => $verifyUrl,
            'clientSignature' => $clientSig,
            'photos' => $photos,
        ]);

        $mpdf = new Mpdf([
            'mode' => 'utf-8', 'format' => 'Letter',
            'margin_left' => 10, 'margin_right' => 10,
            'margin_top' => 12, 'margin_bottom' => 14,
        ]);
        $mpdf->WriteHTML($html);

        $filename = ($report['folio'] ?? ('reporte-' . $id)) . '.pdf';
        $blob = $mpdf->Output($filename, 'S');

        $response = $this->response ?? service('response');

        return $response
            ->setHeader('Content-Type', 'application/pdf')
            ->setHeader('Content-Disposition', ($forceDownload ? 'attachment' : 'inline') . '; filename="' . $filename . '"')
            ->setBody($blob);
    }

    private function normalizePhotoSection(string $section): string
    {
        return match ($section) {
            'antes', 'durante', 'despues' => $section,
            default => 'general',
        };
    }
}
