from __future__ import annotations

import os

from sqlalchemy import inspect, text

from ..extensions import db
from ..models import QuickWin, User
from .app_settings import ensure_app_settings


def ensure_schema_and_admins() -> None:
    inspector = inspect(db.engine)
    column_names = {column["name"] for column in inspector.get_columns("user")}

    if "is_admin" not in column_names:
        db.session.execute(text("ALTER TABLE user ADD COLUMN is_admin BOOLEAN NOT NULL DEFAULT 0"))
        db.session.commit()

    if "calendar_feed_token" not in column_names:
        db.session.execute(text("ALTER TABLE user ADD COLUMN calendar_feed_token VARCHAR(255)"))
        db.session.commit()

    if "notification_badge_enabled" not in column_names:
        db.session.execute(text("ALTER TABLE user ADD COLUMN notification_badge_enabled BOOLEAN NOT NULL DEFAULT 1"))
        db.session.commit()

    task_template_columns = {column["name"] for column in inspector.get_columns("task_template")}
    if "default_assigned_user_secondary_id" not in task_template_columns:
        db.session.execute(text("ALTER TABLE task_template ADD COLUMN default_assigned_user_secondary_id INTEGER"))
        db.session.commit()

    task_instance_columns = {column["name"] for column in inspector.get_columns("task_instance")}
    if "assigned_user_secondary_id" not in task_instance_columns:
        db.session.execute(text("ALTER TABLE task_instance ADD COLUMN assigned_user_secondary_id INTEGER"))
        db.session.commit()

    quick_win_columns = {column["name"] for column in inspector.get_columns("quick_win")}
    if "sort_order" not in quick_win_columns:
        db.session.execute(text("ALTER TABLE quick_win ADD COLUMN sort_order INTEGER NOT NULL DEFAULT 0"))
        db.session.commit()

    ensure_app_settings()

    users_without_feed = User.query.filter(User.calendar_feed_token.is_(None)).all()
    if users_without_feed:
        for user in users_without_feed:
            user.ensure_calendar_feed_token()
        db.session.commit()

    admin_exists = User.query.filter_by(is_admin=True).first()
    default_quick_win_user = admin_exists

    preferred_admin_email = os.getenv("DEFAULT_ADMIN_EMAIL", "mail@hnz.io").lower().strip()
    preferred_user = User.query.filter(User.email.ilike(preferred_admin_email)).first()
    if preferred_user and not admin_exists:
        preferred_user.is_admin = True
        db.session.commit()
        default_quick_win_user = preferred_user

    first_user = User.query.order_by(User.id.asc()).first()
    if first_user and not User.query.filter_by(is_admin=True).first():
        first_user.is_admin = True
        db.session.commit()
        default_quick_win_user = first_user

    _ensure_default_quick_wins(default_quick_win_user or User.query.order_by(User.id.asc()).first())
    _ensure_quick_win_ordering()


def _ensure_default_quick_wins(default_user: User | None) -> None:
    if not default_user:
        return

    defaults = [
        ("Schnell Aufräumen", "fast"),
        ("Spülmaschine ausräumen", "normal"),
        ("Bett machen", "normal"),
        ("Lüften", "fast"),
        ("Wäsche zusammenlegen", "medium"),
    ]

    existing_titles = {quick_win.title for quick_win in QuickWin.query.all()}
    created = False
    next_sort_order = QuickWin.query.count()
    for title, effort in defaults:
        if title not in existing_titles:
            db.session.add(
                QuickWin(
                    title=title,
                    effort=effort,
                    active=True,
                    created_by_user_id=default_user.id,
                    sort_order=next_sort_order,
                )
            )
            next_sort_order += 1
            created = True
    if created:
        db.session.commit()


def _ensure_quick_win_ordering() -> None:
    quick_wins = QuickWin.query.order_by(QuickWin.sort_order.asc(), QuickWin.id.asc()).all()
    dirty = False
    for index, quick_win in enumerate(quick_wins):
        if quick_win.sort_order != index:
            quick_win.sort_order = index
            dirty = True
    if dirty:
        db.session.commit()
