<?php

if (!function_exists('impfTableExists')) {
    function impfTableExists(PDO $pdo, string $table): bool
    {
        $st = $pdo->prepare("SHOW TABLES LIKE :table");
        $st->execute(['table' => $table]);
        return (bool)$st->fetchColumn();
    }
}

if (!function_exists('impfTableHasColumn')) {
    function impfTableHasColumn(PDO $pdo, string $table, string $column): bool
    {
        static $cache = [];

        $cacheKey = $table . '.' . $column;
        if (array_key_exists($cacheKey, $cache)) {
            return $cache[$cacheKey];
        }

        $st = $pdo->prepare("SHOW COLUMNS FROM `" . $table . "` LIKE :column");
        $st->execute(['column' => $column]);
        $cache[$cacheKey] = (bool)$st->fetch(PDO::FETCH_ASSOC);
        return $cache[$cacheKey];
    }
}

if (!function_exists('impfWeekdayName')) {
    function impfWeekdayName(int $day): string
    {
        $map = [
            1 => 'Montag',
            2 => 'Dienstag',
            3 => 'Mittwoch',
            4 => 'Donnerstag',
            5 => 'Freitag',
            6 => 'Samstag',
            7 => 'Sonntag',
        ];

        return $map[$day] ?? 'Unbekannt';
    }
}

if (!function_exists('impfWorkflowEnsureTables')) {
    function impfWorkflowEnsureTables(PDO $pdo): void
    {
        $pdo->exec("CREATE TABLE IF NOT EXISTS impfstoff_workflow (
            impfstoff_id INT NOT NULL,
            dosen_pro_flasche INT NOT NULL,
            updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (impfstoff_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3");

        $pdo->exec("CREATE TABLE IF NOT EXISTS impfstoff_wochenplan (
            plan_id INT NOT NULL AUTO_INCREMENT,
            impfstoff_id INT NOT NULL,
            wochentag TINYINT NOT NULL,
            start TIME NOT NULL,
            ende TIME NOT NULL,
            impfortid INT NOT NULL,
            aktiv TINYINT NOT NULL DEFAULT 1,
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (plan_id),
            INDEX idx_impfstoff_wochenplan_impfstoff (impfstoff_id),
            INDEX idx_impfstoff_wochenplan_wochentag (wochentag)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3");

        $pdo->exec("CREATE TABLE IF NOT EXISTS impf_zeitraum (
            zeitraum_id INT NOT NULL AUTO_INCREMENT,
            bezeichnung VARCHAR(120) NOT NULL DEFAULT '',
            wochentag TINYINT NOT NULL,
            start TIME NOT NULL,
            ende TIME NOT NULL,
            impfortid INT NOT NULL,
            aktiv TINYINT NOT NULL DEFAULT 1,
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (zeitraum_id),
            INDEX idx_impf_zeitraum_wochentag (wochentag),
            INDEX idx_impf_zeitraum_impfort (impfortid)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3");

        if (!impfTableHasColumn($pdo, 'impf_zeitraum', 'bezeichnung')) {
            $pdo->exec("ALTER TABLE impf_zeitraum ADD COLUMN bezeichnung VARCHAR(120) NOT NULL DEFAULT '' AFTER zeitraum_id");
        }

        $pdo->exec("CREATE TABLE IF NOT EXISTS impf_zeitraum_impfstoff (
            zeitraum_id INT NOT NULL,
            impfstoff_id INT NOT NULL,
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY (zeitraum_id, impfstoff_id),
            INDEX idx_impf_zeitraum_impfstoff_impfstoff (impfstoff_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3");

        impfWorkflowMigrateLegacyPlans($pdo);
    }
}

if (!function_exists('impfWorkflowMigrateLegacyPlans')) {
    function impfWorkflowMigrateLegacyPlans(PDO $pdo): void
    {
        if (!impfTableExists($pdo, 'impfstoff_wochenplan')) {
            return;
        }

        $stLegacy = $pdo->query("SELECT plan_id, impfstoff_id, wochentag, start, ende, impfortid, aktiv
                                 FROM impfstoff_wochenplan");
        $legacyRows = $stLegacy ? $stLegacy->fetchAll(PDO::FETCH_ASSOC) : [];
        if (empty($legacyRows)) {
            return;
        }

        $manageTransaction = !$pdo->inTransaction();
        if ($manageTransaction) {
            $pdo->beginTransaction();
        }

        try {
            $stFindZeitraum = $pdo->prepare("SELECT zeitraum_id
                                             FROM impf_zeitraum
                                             WHERE wochentag = :wochentag
                                               AND start = :start
                                               AND ende = :ende
                                               AND impfortid = :impfortid
                                               AND aktiv = :aktiv
                                             LIMIT 1");
            $stInsertZeitraum = $pdo->prepare("INSERT INTO impf_zeitraum
                (bezeichnung, wochentag, start, ende, impfortid, aktiv)
                VALUES
                ('', :wochentag, :start, :ende, :impfortid, :aktiv)");
            $stInsertMap = $pdo->prepare("INSERT INTO impf_zeitraum_impfstoff
                (zeitraum_id, impfstoff_id)
                VALUES
                (:zeitraum_id, :impfstoff_id)
                ON DUPLICATE KEY UPDATE impfstoff_id = VALUES(impfstoff_id)");

            foreach ($legacyRows as $row) {
                $params = [
                    'wochentag' => (int)$row['wochentag'],
                    'start' => (string)$row['start'],
                    'ende' => (string)$row['ende'],
                    'impfortid' => (int)$row['impfortid'],
                    'aktiv' => (int)$row['aktiv'],
                ];

                $stFindZeitraum->execute($params);
                $zeitraumId = (int)($stFindZeitraum->fetchColumn() ?: 0);
                if ($zeitraumId <= 0) {
                    $stInsertZeitraum->execute($params);
                    $zeitraumId = (int)$pdo->lastInsertId();
                }

                if ($zeitraumId > 0 && (int)$row['impfstoff_id'] > 0) {
                    $stInsertMap->execute([
                        'zeitraum_id' => $zeitraumId,
                        'impfstoff_id' => (int)$row['impfstoff_id'],
                    ]);
                }
            }

            if ($manageTransaction) {
                $pdo->commit();
            }
        } catch (Throwable $e) {
            if ($manageTransaction && $pdo->inTransaction()) {
                $pdo->rollBack();
            }
            throw $e;
        }
    }
}

if (!function_exists('impfCsvToIntList')) {
    function impfCsvToIntList(?string $csv): array
    {
        if ($csv === null || trim($csv) === '') {
            return [];
        }

        $werte = array_filter(array_map('trim', explode(',', $csv)), static function ($wert): bool {
            return $wert !== '';
        });

        return array_values(array_map('intval', $werte));
    }
}

if (!function_exists('impfZeitraumLabel')) {
    function impfZeitraumLabel(array $zeitraum): string
    {
        $zeitText = impfWeekdayName((int)$zeitraum['wochentag']) . ' ' . substr((string)$zeitraum['start'], 0, 5) . '-' . substr((string)$zeitraum['ende'], 0, 5);
        $ort = trim((string)($zeitraum['anzeigename'] ?? '') . ' - ' . (string)($zeitraum['adresse'] ?? ''));
        $ortText = trim($ort, " -");
        if ($ortText !== '') {
            $zeitText .= ' (' . $ortText . ')';
        }

        $bezeichnung = trim((string)($zeitraum['bezeichnung'] ?? ''));
        if ($bezeichnung !== '') {
            return $bezeichnung . ': ' . $zeitText;
        }

        return $zeitText;
    }
}

if (!function_exists('impfGetZeitraumRows')) {
    function impfGetZeitraumRows(PDO $pdo, bool $onlyActive = true): array
    {
        $sql = "SELECT z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at,
                       o.anzeigename, o.adresse,
                       GROUP_CONCAT(DISTINCT m.impfstoff_id ORDER BY m.impfstoff_id SEPARATOR ',') AS impfstoff_ids,
                       GROUP_CONCAT(DISTINCT i.impfname ORDER BY i.impfname SEPARATOR '||') AS impfstoff_namen
                FROM impf_zeitraum z
                LEFT JOIN impfort o ON o.ortid = z.impfortid
                LEFT JOIN impf_zeitraum_impfstoff m ON m.zeitraum_id = z.zeitraum_id
                LEFT JOIN impfstoff i ON i.impfid = m.impfstoff_id";
        if ($onlyActive) {
            $sql .= " WHERE z.aktiv = 1";
        }
        $sql .= " GROUP BY z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, o.anzeigename, o.adresse
                  ORDER BY z.wochentag, z.start, z.ende, z.bezeichnung, z.zeitraum_id";

        $st = $pdo->prepare($sql);
        $st->execute();
        $rows = $st->fetchAll(PDO::FETCH_ASSOC);

        foreach ($rows as &$row) {
            $row['impfstoff_id_list'] = impfCsvToIntList($row['impfstoff_ids'] ?? null);
            $row['impfstoff_name_list'] = [];
            if (!empty($row['impfstoff_namen'])) {
                $row['impfstoff_name_list'] = array_values(array_filter(explode('||', (string)$row['impfstoff_namen']), static function ($name): bool {
                    return trim((string)$name) !== '';
                }));
            }
            $row['label'] = impfZeitraumLabel($row);
        }
        unset($row);

        return $rows;
    }
}

if (!function_exists('impfLoadZeitraumById')) {
    function impfLoadZeitraumById(PDO $pdo, int $zeitraumId, bool $onlyActive = true): ?array
    {
        if ($zeitraumId <= 0) {
            return null;
        }

        $sql = "SELECT z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at,
                       o.anzeigename, o.adresse,
                       GROUP_CONCAT(DISTINCT m.impfstoff_id ORDER BY m.impfstoff_id SEPARATOR ',') AS impfstoff_ids,
                       GROUP_CONCAT(DISTINCT i.impfname ORDER BY i.impfname SEPARATOR '||') AS impfstoff_namen
                FROM impf_zeitraum z
                LEFT JOIN impfort o ON o.ortid = z.impfortid
                LEFT JOIN impf_zeitraum_impfstoff m ON m.zeitraum_id = z.zeitraum_id
                LEFT JOIN impfstoff i ON i.impfid = m.impfstoff_id
                WHERE z.zeitraum_id = :zeitraum_id";
        if ($onlyActive) {
            $sql .= " AND z.aktiv = 1";
        }
        $sql .= " GROUP BY z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at, o.anzeigename, o.adresse
                  LIMIT 1";

        $st = $pdo->prepare($sql);
        $st->execute(['zeitraum_id' => $zeitraumId]);
        $row = $st->fetch(PDO::FETCH_ASSOC);
        if (!$row) {
            return null;
        }

        $row['impfstoff_id_list'] = impfCsvToIntList($row['impfstoff_ids'] ?? null);
        $row['impfstoff_name_list'] = [];
        if (!empty($row['impfstoff_namen'])) {
            $row['impfstoff_name_list'] = array_values(array_filter(explode('||', (string)$row['impfstoff_namen']), static function ($name): bool {
                return trim((string)$name) !== '';
            }));
        }
        $row['label'] = impfZeitraumLabel($row);

        return $row;
    }
}

if (!function_exists('impfGetZeitraeumeByImpfstoff')) {
    function impfGetZeitraeumeByImpfstoff(PDO $pdo, bool $onlyActive = true): array
    {
        $zeitraeume = impfGetZeitraumRows($pdo, $onlyActive);
        $result = [];

        foreach ($zeitraeume as $zeitraum) {
            foreach ($zeitraum['impfstoff_id_list'] as $impfstoffId) {
                if (!isset($result[$impfstoffId])) {
                    $result[$impfstoffId] = [];
                }
                $result[$impfstoffId][] = $zeitraum;
            }
        }

        return $result;
    }
}
