<?php

declare(strict_types=1);

final class MyronDocumentTemplateRepository
{
    public function __construct(
        private readonly PDO $pdo,
        private readonly MyronFileRepository $files,
    ) {
    }

    /**
     * @param array<string, mixed> $input
     * @return array<string, mixed>
     */
    public function createFromFile(string $fileId, array $input, string $createdByUserId): array
    {
        $file = $this->files->getFileById($fileId);
        if (!is_array($file) || (string) ($file['media_class'] ?? '') !== 'document') {
            throw new RuntimeException('Document templates must be backed by a document file.');
        }

        $title = trim((string) ($input['title'] ?? $file['title'] ?? $file['original_filename'] ?? ''));
        if ($title === '') {
            throw new RuntimeException('Document template title is required.');
        }

        $templateId = myronGenerateId('dtpl');
        $now = myronNow();
        $statement = $this->pdo->prepare(
            'INSERT INTO document_templates (
                id,
                file_id,
                title,
                description,
                is_active,
                created_by_user_id,
                created_at,
                updated_at
             ) VALUES (
                :id,
                :file_id,
                :title,
                :description,
                1,
                :created_by_user_id,
                :created_at,
                :updated_at
             )'
        );
        $statement->execute([
            ':id' => $templateId,
            ':file_id' => $fileId,
            ':title' => $title,
            ':description' => trim((string) ($input['description'] ?? $file['description'] ?? '')),
            ':created_by_user_id' => $createdByUserId,
            ':created_at' => $now,
            ':updated_at' => $now,
        ]);

        $template = $this->getTemplateById($templateId);
        if (!is_array($template)) {
            throw new RuntimeException('Document template could not be loaded after save.');
        }

        return $template;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function listActiveTemplates(): array
    {
        return $this->listTemplates(true);
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function listTemplates(bool $activeOnly = false): array
    {
        $sql = $this->baseSelectSql();
        if ($activeOnly) {
            $sql .= ' WHERE document_templates.is_active = 1';
        }
        $sql .= ' ORDER BY document_templates.updated_at DESC, document_templates.title ASC';

        $statement = $this->pdo->query($sql);
        $rows = $statement ? $statement->fetchAll() : [];

        return $this->decorateRows(is_array($rows) ? $rows : []);
    }

    /**
     * @return array<string, mixed>|null
     */
    public function getTemplateById(string $templateId): ?array
    {
        $statement = $this->pdo->prepare($this->baseSelectSql() . ' WHERE document_templates.id = :template_id LIMIT 1');
        $statement->execute([':template_id' => $templateId]);
        $row = $statement->fetch();

        if (!is_array($row)) {
            return null;
        }

        $rows = $this->decorateRows([$row]);
        return $rows[0] ?? null;
    }

    /**
     * @param array<string, mixed> $input
     */
    public function updateTemplate(string $templateId, array $input): void
    {
        $template = $this->getTemplateById($templateId);
        if (!is_array($template)) {
            throw new RuntimeException('The selected document template could not be found.');
        }

        $title = trim((string) ($input['title'] ?? $template['title'] ?? ''));
        if ($title === '') {
            throw new RuntimeException('Document template title is required.');
        }

        $statement = $this->pdo->prepare(
            'UPDATE document_templates
             SET title = :title,
                 description = :description,
                 updated_at = :updated_at
             WHERE id = :template_id'
        );
        $statement->execute([
            ':title' => $title,
            ':description' => trim((string) ($input['description'] ?? '')),
            ':updated_at' => myronNow(),
            ':template_id' => $templateId,
        ]);
    }

    public function deactivateTemplate(string $templateId): void
    {
        $template = $this->getTemplateById($templateId);
        if (!is_array($template)) {
            throw new RuntimeException('The selected document template could not be found.');
        }

        $statement = $this->pdo->prepare(
            'UPDATE document_templates
             SET is_active = 0,
                 updated_at = :updated_at
             WHERE id = :template_id'
        );
        $statement->execute([
            ':updated_at' => myronNow(),
            ':template_id' => $templateId,
        ]);
    }

    public function deleteTemplate(string $templateId): void
    {
        $statement = $this->pdo->prepare('DELETE FROM document_templates WHERE id = :template_id');
        $statement->execute([':template_id' => $templateId]);
    }

    private function baseSelectSql(): string
    {
        return 'SELECT
                document_templates.*,
                files.original_filename,
                files.stored_filename,
                files.storage_path,
                files.mime_type,
                files.file_extension,
                files.file_size_bytes,
                files.created_at AS file_created_at,
                users.display_name AS created_by_display_name
             FROM document_templates
             INNER JOIN files ON files.id = document_templates.file_id
             INNER JOIN users ON users.id = document_templates.created_by_user_id';
    }

    /**
     * @param list<array<string, mixed>> $rows
     * @return list<array<string, mixed>>
     */
    private function decorateRows(array $rows): array
    {
        $templates = [];
        foreach ($rows as $row) {
            if (!is_array($row)) {
                continue;
            }

            $fileId = (string) ($row['file_id'] ?? '');
            $row['file_url'] = myronBuildFileStreamUrl($fileId);
            $row['download_url'] = myronBuildFileStreamUrl($fileId, true);
            $row['file_size_label'] = myronFormatFileSize((int) ($row['file_size_bytes'] ?? 0));
            $row['is_active'] = (int) ($row['is_active'] ?? 0) === 1;
            $templates[] = $row;
        }

        return $templates;
    }
}
