<?php

namespace App\Services\Reports;

use App\Models\LateSlipLog;

class SlipPrinterService
{
    public function __construct(
        private SlipPrinterConfigService $configService,
        private SlipPrinterFormatterService $formatter,
        private SlipPrinterPdfService $pdfService
    ) {
    }

    public function print(array $input, ?int $userId): array
    {
        $data = $this->buildData($input, $userId);
        if ($data['student_name'] === '') {
            return ['ok' => false, 'message' => 'Student name is required.'];
        }

        $this->logSlip($data, $userId);

        $lines = $this->formatter->buildSlipLines($data, $this->lineWidth());
        $pdf = $this->pdfService->render($data, $lines, $this->paperOptions($input));

        return [
            'ok' => true,
            'data' => $data,
            'pdf' => $pdf['content'],
            'filename' => $pdf['filename'],
        ];
    }

    public function preview(array $input, ?int $userId): array
    {
        $data = $this->buildData($input, $userId);
        $width = $this->lineWidth();
        $feedLines = $this->configService->printerConfig()['feed_lines'] ?? 3;

        $header = "Al Rahma School at ISGL\nSchool Year: {$data['school_year']}\n\n";
        $body = implode("\n", $this->formatter->buildSlipLines($data, $width));
        $footer = str_repeat("\n", (int) $feedLines);

        return [
            'ok' => true,
            'text' => $header . $body . $footer,
            'width' => $width,
        ];
    }

    public function logs(?string $schoolYear = null, ?string $semester = null): array
    {
        $query = LateSlipLog::query();
        if ($schoolYear !== null && trim($schoolYear) !== '') {
            $query->where('school_year', trim($schoolYear));
        }

        $semester = strtolower(trim((string) $semester));
        if ($semester !== '') {
            if ($semester === 'fall') {
                $query->whereIn('semester', ['fall', '1', 1]);
            } elseif ($semester === 'spring') {
                $query->whereIn('semester', ['spring', '2', 2]);
            }
        }

        $rows = $query->orderByDesc('id')->limit(50)->get()->toArray();

        $out = [];
        foreach ($rows as $row) {
            $dispDate = $this->formatter->formatDisplayDate($row['slip_date'] ?? '');
            if ($dispDate === '') {
                $dispDate = $this->formatter->formatDisplayDate($row['printed_at'] ?? '');
            }

            $dispTime = $this->formatter->formatDisplayTime($row['time_in'] ?? '');

            $out[] = [
                'id' => (int) ($row['id'] ?? 0),
                'school_year' => (string) ($row['school_year'] ?? ''),
                'semester' => (string) ($row['semester'] ?? ''),
                'student_name' => (string) ($row['student_name'] ?? ''),
                'date' => $dispDate,
                'time_in' => $dispTime,
                'grade' => (string) ($row['grade'] ?? ''),
                'reason' => (string) ($row['reason'] ?? ''),
                'admin_name' => (string) ($row['admin_name'] ?? ''),
                'printed_at' => (string) ($row['printed_at'] ?? ''),
            ];
        }

        return $out;
    }

    public function reprint(int $id, ?int $userId): array
    {
        $row = LateSlipLog::query()->find($id);
        if (!$row) {
            return ['ok' => false, 'message' => 'Slip not found.'];
        }

        $data = [
            'school_year' => (string) ($row->school_year ?? ''),
            'student_name' => (string) ($row->student_name ?? ''),
            'date' => $this->formatter->formatDisplayDate($row->slip_date ?? '') ?: date('m/d/Y'),
            'time_in' => $this->formatter->formatDisplayTime($row->time_in ?? '') ?: date('h:i A'),
            'grade' => (string) ($row->grade ?? ''),
            'reason' => (string) ($row->reason ?? ''),
            'admin_name' => (string) ($row->admin_name ?? ''),
        ];

        $adminFromDb = $this->configService->currentAdminName($userId);
        if ($adminFromDb !== '') {
            $data['admin_name'] = $adminFromDb;
        }

        $lines = $this->formatter->buildSlipLines($data, $this->lineWidth());
        $pdf = $this->pdfService->render($data, $lines, []);

        $this->logSlip($data, $userId);

        return [
            'ok' => true,
            'data' => $data,
            'pdf' => $pdf['content'],
            'filename' => $pdf['filename'],
        ];
    }

    private function buildData(array $input, ?int $userId): array
    {
        $context = $this->configService->context();
        $schoolYear = trim((string) ($input['school_year'] ?? $context['school_year'] ?? ''));

        $data = [
            'school_year' => $schoolYear,
            'student_name' => trim((string) ($input['student_name'] ?? '')),
            'date' => trim((string) ($input['date'] ?? date('m/d/Y'))),
            'time_in' => trim((string) ($input['time_in'] ?? date('h:i A'))),
            'grade' => trim((string) ($input['grade'] ?? '')),
            'reason' => trim((string) ($input['reason'] ?? '')),
            'admin_name' => trim((string) ($input['admin_name'] ?? '')),
        ];

        $adminFromDb = $this->configService->currentAdminName($userId);
        if ($adminFromDb !== '') {
            $data['admin_name'] = $adminFromDb;
        }

        return $data;
    }

    private function logSlip(array $data, ?int $userId): void
    {
        $context = $this->configService->context();
        $logData = [
            'school_year' => $data['school_year'],
            'semester' => (string) ($context['semester'] ?? ''),
            'student_name' => $data['student_name'],
            'slip_date' => $this->formatter->toDbDate($data['date']),
            'time_in' => $this->formatter->toDbTime($data['time_in']),
            'grade' => $data['grade'],
            'reason' => $data['reason'],
            'admin_name' => $data['admin_name'],
        ];

        LateSlipLog::logSlip($logData, $userId);
    }

    private function lineWidth(): int
    {
        $cfg = $this->configService->printerConfig();
        $width = (int) ($cfg['chars_per_line'] ?? 48);
        return $width > 0 ? $width : 48;
    }

    private function paperOptions(array $input): array
    {
        return [
            'paper' => $input['paper'] ?? null,
            'font_pt' => $input['font_pt'] ?? null,
            'line_h' => $input['line_h'] ?? null,
            'rows' => $input['rows'] ?? null,
            'height_mm' => $input['height_mm'] ?? null,
            'h' => $input['h'] ?? null,
            'fudge_mm' => $input['fudge_mm'] ?? null,
        ];
    }
}
