<?php

namespace App\Services\Reports\Stickers;

use Illuminate\Support\Facades\Log;

class StickerPrintService
{
    public function __construct(private StickerQueryService $queryService)
    {
    }

    public function generate(array $payload): array
    {
        $schoolYear = $this->queryService->resolveSchoolYear($payload['school_year'] ?? null);
        if ($schoolYear === '') {
            Log::error('Sticker print requested without school year.');
        }

        $studentId = (int) ($payload['student_id'] ?? 0);
        $classSectionId = (int) ($payload['class_section_id'] ?? $payload['class_id'] ?? 0);
        $printAll = (bool) ($payload['print_all'] ?? false);

        if ($studentId > 0) {
            $student = $this->queryService->findStudent($studentId);
            if (!$student) {
                return ['ok' => false, 'message' => 'Student not found.'];
            }
            $students = [$student];
        } elseif ($classSectionId > 0) {
            $students = $this->queryService->listStudentsByClass($classSectionId, $schoolYear);
            if (empty($students)) {
                return ['ok' => false, 'message' => 'No students found in this class.'];
            }
        } elseif ($printAll) {
            $students = $this->queryService->listStudentsForPrintAll($schoolYear);
            if (empty($students)) {
                return ['ok' => false, 'message' => 'No students found for this school year.'];
            }
        } else {
            return ['ok' => false, 'message' => 'Please select a student or class.'];
        }

        $printList = $this->expandCopies($students, $payload, $studentId > 0);
        if (empty($printList)) {
            return ['ok' => false, 'message' => 'Nothing to print. All quantities are zero.'];
        }

        $layout = $this->buildLayout($payload);

        $pdf = new \FPDF($layout['orientation'], 'mm', $layout['page_size']);
        $pdf->SetMargins($layout['margin_left'], $layout['margin_top'], $layout['margin_right']);
        $pdf->SetAutoPageBreak(true, $layout['margin_bottom']);
        $pdf->AddPage();
        $pdf->SetFont('Arial', '', 12);

        $pageW = (float) $pdf->GetPageWidth();
        $pageH = (float) $pdf->GetPageHeight();

        $usableW = max(0.0, $pageW - ($layout['margin_left'] + $layout['margin_right']));
        $usableH = max(0.0, $pageH - ($layout['margin_top'] + $layout['margin_bottom']));

        $cols = (int) floor(($usableW + max(0.0, $layout['gap_x'])) / (max(0.1, $layout['sticker_width']) + max(0.0, $layout['gap_x'])));
        $rows = (int) floor(($usableH + max(0.0, $layout['gap_y'])) / (max(0.1, $layout['sticker_height']) + max(0.0, $layout['gap_y'])));

        $cols = max(1, $cols);
        $rows = max(1, $rows);

        $capacity = $cols * $rows;
        if ($layout['stickers_per_page'] > 0 && $layout['stickers_per_page'] < $capacity) {
            $rows = (int) ceil($layout['stickers_per_page'] / $cols);
            $maxRowsFit = (int) floor(($usableH + max(0.0, $layout['gap_y'])) / (max(0.1, $layout['sticker_height']) + max(0.0, $layout['gap_y'])));
            $rows = max(1, min($rows, max(1, $maxRowsFit)));
            $capacity = $cols * $rows;
        }

        $xStart = $layout['margin_left'];
        $yStart = $layout['margin_top'];
        $x = $xStart;
        $y = $yStart;

        $ptToMm = static function (float $pt): float {
            return $pt * 0.352778;
        };

        $i = 0;
        $perPage = $capacity;

        foreach ($printList as $student) {
            if ($i > 0 && $i % $perPage === 0) {
                $pdf->AddPage();
                $x = $xStart;
                $y = $yStart;
            }

            $pdf->SetFillColor(255, 255, 255);
            $pdf->Rect($x, $y, $layout['sticker_width'], $layout['sticker_height'], 'F');

            $fontFamily = 'Arial';
            $fontStyle = 'B';
            $maxPt = 16;
            $minPt = 8;
            $hPad = 2;

            $fullName = trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')) ?: 'Student';

            $bestPt = $maxPt;
            $textW = 0.0;
            while ($bestPt >= $minPt) {
                $pdf->SetFont($fontFamily, $fontStyle, $bestPt);
                $textW = (float) $pdf->GetStringWidth($fullName);
                if ($textW <= ($layout['sticker_width'] - 2 * $hPad)) {
                    break;
                }
                $bestPt -= 0.5;
            }
            if ($bestPt < $minPt) {
                $bestPt = $minPt;
                $pdf->SetFont($fontFamily, $fontStyle, $bestPt);
                $textW = (float) $pdf->GetStringWidth($fullName);
            }
            $textH = $ptToMm($bestPt);

            $cellX = $x + (($layout['sticker_width'] - $textW) / 2);
            $cellY = $y + (($layout['sticker_height'] - $textH) / 2);

            $pdf->SetXY($cellX, $cellY);
            $pdf->Cell($textW, $textH, $fullName, 0, 0, 'L');

            $i++;
            $posInRow = ($i - 1) % $cols;
            if ($posInRow === ($cols - 1)) {
                $x = $xStart;
                $y += $layout['sticker_height'] + $layout['gap_y'];
            } else {
                $x += $layout['sticker_width'] + $layout['gap_x'];
            }
        }

        return [
            'ok' => true,
            'pdf' => $pdf->Output('S'),
            'filename' => 'Student_Stickers.pdf',
        ];
    }

    private function expandCopies(array $students, array $payload, bool $singleStudentMode): array
    {
        $copiesPosted = $payload['copies'] ?? null;
        $singleCopies = (int) ($payload['single_copies'] ?? 1);
        if ($singleCopies < 0) {
            $singleCopies = 0;
        }

        $printList = [];
        if ($singleStudentMode) {
            $qty = max(0, $singleCopies);
            for ($k = 0; $k < $qty; $k++) {
                $printList[] = $students[0];
            }
            return $printList;
        }

        $hasCopies = is_array($copiesPosted);
        $defaultQty = $hasCopies ? 0 : 1;
        foreach ($students as $student) {
            $id = (int) ($student['id'] ?? 0);
            $qty = $defaultQty;
            if ($hasCopies && array_key_exists((string) $id, $copiesPosted)) {
                $qty = (int) $copiesPosted[(string) $id];
            }
            $qty = max(0, $qty);
            for ($k = 0; $k < $qty; $k++) {
                $printList[] = $student;
            }
        }

        return $printList;
    }

    private function buildLayout(array $payload): array
    {
        $sizeStrReq = trim((string) ($payload['sticker_size'] ?? ''));
        $stickerWidth = (float) ($payload['sticker_width'] ?? 0);
        $stickerHeight = (float) ($payload['sticker_height'] ?? 0);

        if (($stickerWidth <= 0 || $stickerHeight <= 0) && $sizeStrReq !== '') {
            if (preg_match('/^\\s*(\\d+(?:\\.\\d+)?)\\s*[xX\\x{00D7}]\\s*(\\d+(?:\\.\\d+)?)\\s*$/u', $sizeStrReq, $m)) {
                $stickerWidth = (float) $m[1];
                $stickerHeight = (float) $m[2];
            }
        }

        if ($stickerWidth <= 0) {
            $stickerWidth = 102.0;
        }
        if ($stickerHeight <= 0) {
            $stickerHeight = 34.0;
        }

        $stickersPerPage = (int) ($payload['stickers_per_page'] ?? 0);
        $pageSize = (string) ($payload['page_size'] ?? 'A4');
        $orientation = (string) ($payload['orientation'] ?? 'P');

        $marginLeftProvided = array_key_exists('margin_left', $payload);
        $marginTopProvided = array_key_exists('margin_top', $payload);
        $marginRightProvided = array_key_exists('margin_right', $payload);
        $marginBottomProvided = array_key_exists('margin_bottom', $payload);
        $gapXProvided = array_key_exists('gap_x', $payload);
        $gapYProvided = array_key_exists('gap_y', $payload);

        $marginLeft = (float) ($payload['margin_left'] ?? 6);
        $marginTop = (float) ($payload['margin_top'] ?? 6);
        $marginRight = (float) ($payload['margin_right'] ?? $marginLeft);
        $marginBottom = (float) ($payload['margin_bottom'] ?? 10);
        $gapX = (float) ($payload['gap_x'] ?? 0);
        $gapY = (float) ($payload['gap_y'] ?? 0);

        $normalizedSize = strtolower(str_replace(["\x{00D7}", ' '], ['x', ''], $sizeStrReq));
        $isXSmallPreset = $normalizedSize === '100x24.5'
            || (abs($stickerWidth - 100.0) < 0.6 && abs($stickerHeight - 24.5) < 0.6);

        if ($isXSmallPreset) {
            if (!$marginLeftProvided) {
                $marginLeft = 4.0;
                if (!$marginRightProvided) {
                    $marginRight = 4.0;
                }
            }
            if (!$marginRightProvided && $marginRight < 4.0) {
                $marginRight = 4.0;
            }
            if (!$gapXProvided) {
                $gapX = 0.0;
            }
            if (!$gapYProvided) {
                $gapY = 0.0;
            }
        }

        return [
            'sticker_width' => $stickerWidth,
            'sticker_height' => $stickerHeight,
            'stickers_per_page' => $stickersPerPage,
            'page_size' => $pageSize,
            'orientation' => $orientation,
            'margin_left' => $marginLeft,
            'margin_top' => $marginTop,
            'margin_right' => $marginRight,
            'margin_bottom' => $marginBottom,
            'gap_x' => $gapX,
            'gap_y' => $gapY,
        ];
    }
}
