<?php
class ProfessionalDayOff
{
    public static function ensureTable(): void
    {
        $pdo = Database::pdo();
        if (Database::driver() === 'mysql') {
            $pdo->exec("CREATE TABLE IF NOT EXISTS professional_days_off (
                id INT AUTO_INCREMENT PRIMARY KEY,
                professional_id INT NOT NULL,
                off_date DATE NOT NULL,
                recurrence_days INT NOT NULL DEFAULT 0,
                note VARCHAR(255) NULL,
                is_active TINYINT(1) NOT NULL DEFAULT 1,
                created_at DATETIME NOT NULL,
                INDEX idx_prof_dayoff_prof (professional_id),
                INDEX idx_prof_dayoff_date (off_date),
                CONSTRAINT fk_prof_dayoff_prof FOREIGN KEY (professional_id) REFERENCES professionals(id) ON DELETE CASCADE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
        } else {
            $pdo->exec("CREATE TABLE IF NOT EXISTS professional_days_off (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                professional_id INTEGER NOT NULL,
                off_date TEXT NOT NULL,
                recurrence_days INTEGER NOT NULL DEFAULT 0,
                note TEXT NULL,
                is_active INTEGER NOT NULL DEFAULT 1,
                created_at TEXT NOT NULL,
                FOREIGN KEY (professional_id) REFERENCES professionals(id) ON DELETE CASCADE
            )");
            $pdo->exec('CREATE INDEX IF NOT EXISTS idx_prof_dayoff_prof ON professional_days_off(professional_id)');
            $pdo->exec('CREATE INDEX IF NOT EXISTS idx_prof_dayoff_date ON professional_days_off(off_date)');
        }
    }

    public static function save(int $professionalId, string $offDate, int $recurrenceDays = 0, string $note = ''): array
    {
        Database::migrate();
        self::ensureTable();
        $offDate = trim($offDate);
        $recurrenceDays = in_array($recurrenceDays, [0, 8, 15], true) ? $recurrenceDays : 0;
        if ($professionalId <= 0 || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $offDate)) {
            return ['ok' => false, 'message' => 'Informe o instrutor e uma data válida para a folga.'];
        }
        if (!Professional::find($professionalId)) {
            return ['ok' => false, 'message' => 'Instrutor não encontrado.'];
        }
        $stmt = Database::pdo()->prepare('INSERT INTO professional_days_off (professional_id, off_date, recurrence_days, note, is_active, created_at) VALUES (?, ?, ?, ?, 1, ?)');
        $stmt->execute([$professionalId, $offDate, $recurrenceDays, trim($note), date('Y-m-d H:i:s')]);
        return ['ok' => true, 'message' => $recurrenceDays > 0 ? 'Folga recorrente cadastrada com sucesso.' : 'Folga cadastrada com sucesso.'];
    }

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

    public static function allRules(): array
    {
        Database::migrate();
        self::ensureTable();
        $stmt = Database::pdo()->query("SELECT d.*, p.name AS professional_name, p.type AS professional_type
            FROM professional_days_off d
            INNER JOIN professionals p ON p.id = d.professional_id
            WHERE d.is_active = 1
            ORDER BY d.off_date ASC, p.name ASC, d.id ASC");
        return $stmt->fetchAll();
    }

    public static function isOff(int $professionalId, string $date): ?array
    {
        Database::migrate();
        self::ensureTable();
        if ($professionalId <= 0 || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return null;
        }
        $stmt = Database::pdo()->prepare('SELECT * FROM professional_days_off WHERE professional_id = ? AND is_active = 1 AND off_date <= ? ORDER BY off_date DESC, id DESC');
        $stmt->execute([$professionalId, $date]);
        foreach ($stmt->fetchAll() as $rule) {
            $start = DateTimeImmutable::createFromFormat('!Y-m-d', (string)$rule['off_date']);
            $target = DateTimeImmutable::createFromFormat('!Y-m-d', $date);
            if (!$start || !$target || $target < $start) {
                continue;
            }
            $recurrence = (int)($rule['recurrence_days'] ?? 0);
            if ($recurrence <= 0 && $date === (string)$rule['off_date']) {
                return $rule;
            }
            if ($recurrence > 0) {
                $days = (int)$start->diff($target)->format('%a');
                if ($days % $recurrence === 0) {
                    return $rule;
                }
            }
        }
        return null;
    }

    public static function upcomingForProfessional(int $professionalId, int $daysAhead = 90): array
    {
        Database::migrate();
        self::ensureTable();
        $daysAhead = max(1, min(365, $daysAhead));
        $today = new DateTimeImmutable('today');
        $end = $today->modify('+' . $daysAhead . ' days');
        $items = [];
        $stmt = Database::pdo()->prepare('SELECT * FROM professional_days_off WHERE professional_id = ? AND is_active = 1 ORDER BY off_date ASC, id ASC');
        $stmt->execute([$professionalId]);
        foreach ($stmt->fetchAll() as $rule) {
            $start = DateTimeImmutable::createFromFormat('!Y-m-d', (string)$rule['off_date']);
            if (!$start) continue;
            $recurrence = (int)($rule['recurrence_days'] ?? 0);
            if ($recurrence <= 0) {
                if ($start >= $today && $start <= $end) {
                    $items[] = $rule + ['occurrence_date' => $start->format('Y-m-d')];
                }
                continue;
            }
            $cursor = $start;
            if ($cursor < $today) {
                $elapsed = (int)$cursor->diff($today)->format('%a');
                $steps = intdiv($elapsed, $recurrence);
                $cursor = $cursor->modify('+' . ($steps * $recurrence) . ' days');
                while ($cursor < $today) $cursor = $cursor->modify('+' . $recurrence . ' days');
            }
            while ($cursor <= $end && count($items) < 40) {
                $items[] = $rule + ['occurrence_date' => $cursor->format('Y-m-d')];
                $cursor = $cursor->modify('+' . $recurrence . ' days');
            }
        }
        usort($items, static fn(array $a, array $b): int => strcmp((string)$a['occurrence_date'], (string)$b['occurrence_date']));
        return array_slice($items, 0, 20);
    }
}
