<?php
class Holiday
{
    public static function ensureTable(): void
    {
        $pdo = Database::pdo();
        if (Database::driver() === 'mysql') {
            $pdo->exec("CREATE TABLE IF NOT EXISTS holidays (
                id INT AUTO_INCREMENT PRIMARY KEY,
                holiday_date DATE NOT NULL,
                name VARCHAR(180) NOT NULL,
                type VARCHAR(20) NOT NULL DEFAULT 'national',
                uf VARCHAR(2) NULL,
                city VARCHAR(120) NULL,
                repeat_yearly TINYINT(1) NOT NULL DEFAULT 0,
                is_active TINYINT(1) NOT NULL DEFAULT 1,
                created_at DATETIME NOT NULL,
                INDEX idx_holidays_date (holiday_date),
                INDEX idx_holidays_scope (type, uf, city, is_active),
                INDEX idx_holidays_repeat (repeat_yearly, is_active)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
            try { $pdo->exec("ALTER TABLE holidays ADD COLUMN repeat_yearly TINYINT(1) NOT NULL DEFAULT 0"); } catch (Throwable $e) {}
        } else {
            $pdo->exec("CREATE TABLE IF NOT EXISTS holidays (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                holiday_date TEXT NOT NULL,
                name TEXT NOT NULL,
                type TEXT NOT NULL DEFAULT 'national',
                uf TEXT NULL,
                city TEXT NULL,
                repeat_yearly INTEGER NOT NULL DEFAULT 0,
                is_active INTEGER NOT NULL DEFAULT 1,
                created_at TEXT NOT NULL
            )");
            try { $pdo->exec("ALTER TABLE holidays ADD COLUMN repeat_yearly INTEGER NOT NULL DEFAULT 0"); } catch (Throwable $e) {}
            $pdo->exec('CREATE INDEX IF NOT EXISTS idx_holidays_date ON holidays(holiday_date)');
            $pdo->exec('CREATE INDEX IF NOT EXISTS idx_holidays_scope ON holidays(type, uf, city, is_active)');
            $pdo->exec('CREATE INDEX IF NOT EXISTS idx_holidays_repeat ON holidays(repeat_yearly, is_active)');
        }
    }

    public static function typeLabel(string $type): string
    {
        return match ($type) {
            'state' => 'Estadual',
            'city' => 'Municipal',
            default => 'Nacional',
        };
    }

    public static function recurrenceLabel(array $holiday): string
    {
        return !empty($holiday['repeat_yearly']) ? 'Recorrente todo ano' : 'Somente neste ano';
    }

    public static function all(): array
    {
        Database::migrate();
        self::ensureTable();
        $stmt = Database::pdo()->query("SELECT * FROM holidays ORDER BY holiday_date DESC, id DESC LIMIT 500");
        return $stmt->fetchAll();
    }

    public static function activeAll(): array
    {
        Database::migrate();
        self::ensureTable();
        $stmt = Database::pdo()->query("SELECT * FROM holidays WHERE is_active = 1 ORDER BY holiday_date ASC, id ASC LIMIT 1000");
        return $stmt->fetchAll();
    }

    public static function save(array $data): array
    {
        Database::migrate();
        self::ensureTable();
        $id = (int)($data['holiday_id'] ?? 0);
        $date = trim($data['holiday_date'] ?? '');
        $name = trim($data['name'] ?? '');
        $type = trim($data['type'] ?? 'national');
        $uf = strtoupper(trim($data['uf'] ?? ''));
        $city = trim($data['city'] ?? '');
        $repeatYearly = !empty($data['repeat_yearly']) ? 1 : 0;
        $active = !empty($data['is_active']) ? 1 : 0;

        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return ['ok' => false, 'message' => 'Informe uma data válida para o feriado ou data comemorativa.'];
        }
        if ($name === '') {
            return ['ok' => false, 'message' => 'Informe o nome do feriado ou data comemorativa.'];
        }
        if (!in_array($type, ['national', 'state', 'city'], true)) {
            $type = 'national';
        }
        if ($type === 'state' && $uf === '') {
            return ['ok' => false, 'message' => 'Para feriado estadual, informe a UF.'];
        }
        if ($type === 'city' && ($uf === '' || $city === '')) {
            return ['ok' => false, 'message' => 'Para feriado municipal, informe UF e cidade.'];
        }

        $pdo = Database::pdo();
        if ($id > 0) {
            $stmt = $pdo->prepare('UPDATE holidays SET holiday_date=?, name=?, type=?, uf=?, city=?, repeat_yearly=?, is_active=? WHERE id=?');
            $stmt->execute([$date, $name, $type, $uf ?: null, $city ?: null, $repeatYearly, $active, $id]);
            return ['ok' => true, 'message' => 'Feriado/data comemorativa atualizado com sucesso.'];
        }

        $stmt = $pdo->prepare('INSERT INTO holidays (holiday_date, name, type, uf, city, repeat_yearly, is_active, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
        $stmt->execute([$date, $name, $type, $uf ?: null, $city ?: null, $repeatYearly, $active, date('Y-m-d H:i:s')]);
        return ['ok' => true, 'message' => 'Feriado/data comemorativa cadastrado com sucesso.'];
    }

    public static function delete(int $id): bool
    {
        self::ensureTable();
        $stmt = Database::pdo()->prepare('DELETE FROM holidays WHERE id = ?');
        $stmt->execute([$id]);
        return $stmt->rowCount() > 0;
    }

    public static function appliesToDate(array $holiday, string $date): bool
    {
        $holidayDate = (string)($holiday['holiday_date'] ?? '');
        if ($holidayDate === $date) {
            return true;
        }
        if (!empty($holiday['repeat_yearly']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $holidayDate) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return substr($holidayDate, 5) === substr($date, 5);
        }
        return false;
    }

    public static function appliesToPlace(array $holiday, string $uf = '', string $city = ''): bool
    {
        $type = $holiday['type'] ?? 'national';
        $uf = strtoupper(trim($uf));
        $city = trim($city);

        if ($type === 'national') {
            return true;
        }
        if ($type === 'state') {
            return strtoupper((string)($holiday['uf'] ?? '')) === $uf;
        }
        if ($type === 'city') {
            return strtoupper((string)($holiday['uf'] ?? '')) === $uf
                && mb_strtolower((string)($holiday['city'] ?? ''), 'UTF-8') === mb_strtolower($city, 'UTF-8');
        }
        return false;
    }

    public static function occurrencesForMonth(string $month, string $uf = '', string $city = ''): array
    {
        Database::migrate();
        self::ensureTable();
        if (!preg_match('/^\d{4}-\d{2}$/', $month)) {
            $month = date('Y-m');
        }

        $items = self::activeAll();
        $out = [];
        foreach ($items as $holiday) {
            if (!self::appliesToPlace($holiday, $uf, $city)) {
                continue;
            }

            $holidayDate = (string)($holiday['holiday_date'] ?? '');
            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $holidayDate)) {
                continue;
            }

            $occurrenceDate = $holidayDate;
            if (!empty($holiday['repeat_yearly'])) {
                $occurrenceDate = substr($month, 0, 4) . '-' . substr($holidayDate, 5);
            }

            if (substr($occurrenceDate, 0, 7) !== $month) {
                continue;
            }

            $copy = $holiday;
            $copy['original_holiday_date'] = $holidayDate;
            $copy['holiday_date'] = $occurrenceDate;
            $out[] = $copy;
        }

        usort($out, static fn($a, $b) => strcmp((string)$a['holiday_date'], (string)$b['holiday_date']));
        return $out;
    }

    public static function occurrencesForMonthAdminAll(string $month): array
    {
        Database::migrate();
        self::ensureTable();

        if (!preg_match('/^\d{4}-\d{2}$/', $month)) {
            $month = date('Y-m');
        }

        $items = self::activeAll();
        $out = [];

        foreach ($items as $holiday) {
            $holidayDate = (string)($holiday['holiday_date'] ?? '');
            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $holidayDate)) {
                continue;
            }

            $occurrenceDate = $holidayDate;
            if (!empty($holiday['repeat_yearly'])) {
                $occurrenceDate = substr($month, 0, 4) . '-' . substr($holidayDate, 5);
            }

            if (substr($occurrenceDate, 0, 7) !== $month) {
                continue;
            }

            $copy = $holiday;
            $copy['original_holiday_date'] = $holidayDate;
            $copy['holiday_date'] = $occurrenceDate;
            $out[] = $copy;
        }

        usort($out, static fn($a, $b) => strcmp((string)$a['holiday_date'], (string)$b['holiday_date']));
        return $out;
    }

    public static function occurrencesForDateAdminAll(string $date): array
    {
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return [];
        }

        return array_values(array_filter(
            self::occurrencesForMonthAdminAll(substr($date, 0, 7)),
            static fn($holiday) => ($holiday['holiday_date'] ?? '') === $date
        ));
    }

    public static function byMonth(string $month, string $uf = '', string $city = ''): array
    {
        return self::occurrencesForMonth($month, $uf, $city);
    }

    public static function findForDate(string $date, string $uf = '', string $city = ''): ?array
    {
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return null;
        }
        $month = substr($date, 0, 7);
        foreach (self::byMonth($month, $uf, $city) as $holiday) {
            if (($holiday['holiday_date'] ?? '') === $date) {
                return $holiday;
            }
        }
        return null;
    }
}
