"""Anki domain services."""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import date

from .entities import Card, Deck, ReviewRecord
from .enums import ReviewRating
from .exceptions import InvalidCardError, InvalidDeckError
from .policies import DefaultSchedulingPolicy, SchedulingPolicy


@dataclass
class ReviewService:
    scheduling_policy: SchedulingPolicy = field(default_factory=DefaultSchedulingPolicy)

    def review(self, card: Card, rating: ReviewRating, reviewed_on: date | None = None) -> ReviewRecord:
        if not isinstance(card, Card):
            raise InvalidCardError("card must be a Card instance")

        plan = self.scheduling_policy.schedule(card, rating, reviewed_on=reviewed_on)
        record = ReviewRecord(
            reviewed_on=plan.reviewed_on,
            rating=rating,
            previous_state=card.state,
            next_state=plan.next_state,
            previous_interval_days=card.interval_days,
            next_interval_days=plan.interval_days,
            previous_ease_factor=card.ease_factor,
            next_ease_factor=plan.ease_factor,
            previous_due_at=card.due_at,
            next_due_at=plan.due_at,
            previous_repetitions=card.repetitions,
            next_repetitions=plan.repetitions,
            previous_lapses=card.lapses,
            next_lapses=plan.lapses,
        )
        card.state = plan.next_state
        card.interval_days = plan.interval_days
        card.ease_factor = plan.ease_factor
        card.repetitions = plan.repetitions
        card.lapses = plan.lapses
        card.due_at = plan.due_at
        card.review_history.append(record)
        return record


@dataclass
class DeckService:
    review_service: ReviewService = field(default_factory=ReviewService)

    def add_card(self, deck: Deck, card: Card) -> Card:
        if not isinstance(deck, Deck):
            raise InvalidDeckError("deck must be a Deck instance")
        return deck.add_card(card)

    def due_cards(self, deck: Deck, on_date: date | None = None) -> list[Card]:
        if not isinstance(deck, Deck):
            raise InvalidDeckError("deck must be a Deck instance")
        return deck.due_cards(on_date)

    def review_card(self, card: Card, rating: ReviewRating, reviewed_on: date | None = None) -> ReviewRecord:
        return self.review_service.review(card, rating, reviewed_on=reviewed_on)
