import argparse
import datetime
import os
import shutil
from pathlib import Path

from sqlalchemy import func, select
from sqlalchemy.orm import Session

from meal_manager.main import engine, sqlite_file_name
from meal_manager.models import Event, Registration, Subscription


def backup_db():
    backup_dir = Path(os.environ.get("MEAL_MANAGER_BACKUP_DIR", None))
    shutil.copy2(
        sqlite_file_name,
        backup_dir / f"{sqlite_file_name}.{datetime.datetime.now().isoformat()}",
    )
    # TODO: Delete old backups


def run_nightly_tasks():
    print("Applying Subscriptions")
    with Session(engine) as session:
        apply_subscriptions(session)

    print("Running db backup")
    backup_db()

    print("Done running nightly tasks.")


def apply_subscriptions(
    session: Session, event: Event | None = None, dry_run: bool = False
):

    subscriptions = session.scalars(select(Subscription)).all()

    if event is not None:
        events = [event]
    else:
        today = datetime.date.today()
        query = select(Event).where(
            ~Event.subscriptions_applied,
            ~Event.ignore_subscriptions,
            func.strftime("%Y-%m-%d", Event.event_time) >= today.strftime("%Y-%m-%d"),
            func.strftime("%Y-%m-%d", Event.event_time)
            <= (today + datetime.timedelta(days=7)).strftime("%Y-%m-%d"),
        )
        events = session.scalars(query).all()

    if len(events) == 0:
        print("No events to process")
        return

    for event in events:
        if dry_run:
            print(f"DRY RUN: Would process event {event.title} ({event.id})")
        else:
            print(f"Processing event {event.title} ({event.id})")

        print(f"There are {len(subscriptions)} subscriptions to process")
        relevant_subscriptions = [
            s for s in subscriptions if s.valid_on(event.event_time.date())
        ]
        print(f"{len(relevant_subscriptions)} of them are relevant to this event")

        for subscription in relevant_subscriptions:
            existing_registration = session.scalars(
                select(Registration).where(
                    Registration.event_id == event.id,
                    Registration.household_id == subscription.household_id,
                )
            ).one_or_none()
            if existing_registration:
                print(
                    f"There is already a registration for {subscription.household.name}. Skipping subscription."
                )
                continue

            comment = "Dauerhafte Anmeldung"
            if subscription.comment:
                comment += f" mit Kommentar: {subscription.comment}"

            reg = Registration(
                event_id=event.id,
                household_id=subscription.household_id,
                num_adult_meals=subscription.num_adult_meals,
                num_children_meals=subscription.num_children_meals,
                num_small_children_meals=subscription.num_small_children_meals,
                comment=comment,
            )
            if dry_run:
                print(f"DRY RUN: Would register {subscription.household.name}")
            else:
                session.add(reg)
                print(f"Registered {subscription.household.name}")
            event.subscriptions_applied = True

    if not dry_run:
        session.commit()


def apply_subscriptions_cli():
    parser = argparse.ArgumentParser(description="Apply subscriptions for an event")
    parser.add_argument("--event_id", type=int, help="Event ID (required)")
    parser.add_argument(
        "--dry-run", action="store_true", help="Run without making changes"
    )

    args = parser.parse_args()

    # Access the arguments
    event_id = args.event_id
    dry_run = args.dry_run

    with Session(engine) as session:
        if event_id is not None:
            event = session.scalars(select(Event).where(Event.id == event_id)).one()
            apply_subscriptions(session, event, dry_run)
        else:
            apply_subscriptions(session, dry_run=dry_run)
