from sqlalchemy import select

from .models import filtersettings
from .engine import async_session
from app.schedule_utils import (
    DEFAULT_WORK_DAYS,
    DEFAULT_WORK_FROM,
    DEFAULT_WORK_TO,
    RUN_MODE_MANUAL,
    RUN_MODE_SCHEDULE,
    format_hhmm,
    normalize_work_days,
)


def _schedule_defaults(record: filtersettings) -> None:
    """Подставляет defaults для старых строк без колонок/значений."""
    if not getattr(record, "run_mode", None):
        record.run_mode = RUN_MODE_MANUAL
    if not getattr(record, "work_from", None):
        record.work_from = DEFAULT_WORK_FROM
    if not getattr(record, "work_to", None):
        record.work_to = DEFAULT_WORK_TO
    if getattr(record, "work_days", None) is None:
        record.work_days = list(DEFAULT_WORK_DAYS)


def _record_to_dict(record: filtersettings) -> dict:
    _schedule_defaults(record)
    return {
        "user_id": record.user_id,
        "typeavto": record.typeavto,
        "region_id": record.region_id,
        "year_first": record.year_first,
        "year_second": record.year_second,
        "price_first": record.price_first,
        "price_second": record.price_second,
        "run_mode": record.run_mode or RUN_MODE_MANUAL,
        "work_from": format_hhmm(record.work_from, DEFAULT_WORK_FROM),
        "work_to": format_hhmm(record.work_to, DEFAULT_WORK_TO),
        "work_days": normalize_work_days(record.work_days),
    }


# Функция добавления записи. Если запись с таким user_id уже существует, возвращаем её.
async def add_filtersettings(
    user_id: int,
    typeavto: str,
    region_id,
    year_first: int = None,
    year_second: int = None,
    price_first: float = None,
    price_second: float = None,
) -> filtersettings:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            existing = result.scalars().first()
            if existing:
                if not existing.run_mode:
                    existing.run_mode = RUN_MODE_MANUAL
                if not existing.work_from:
                    existing.work_from = DEFAULT_WORK_FROM
                if not existing.work_to:
                    existing.work_to = DEFAULT_WORK_TO
                if existing.work_days is None:
                    existing.work_days = list(DEFAULT_WORK_DAYS)
                return existing
            new_record = filtersettings(
                user_id=user_id,
                typeavto=typeavto,
                region_id=region_id,
                year_first=year_first,
                year_second=year_second,
                price_first=price_first,
                price_second=price_second,
                run_mode=RUN_MODE_MANUAL,
                work_from=DEFAULT_WORK_FROM,
                work_to=DEFAULT_WORK_TO,
                work_days=list(DEFAULT_WORK_DAYS),
            )
            session.add(new_record)
        return new_record


async def reset_filter_settings(user_id: int) -> bool:
    """Сброс полей фильтра объявлений (расписание не трогаем)."""
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if not record:
                return False
            record.typeavto = "1"
            record.region_id = []
            record.year_first = None
            record.year_second = None
            record.price_first = None
            record.price_second = None
            return True


async def update_typeavto(user_id: int, new_typeavto: str) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.typeavto = new_typeavto
                return True
            return False


async def update_region_id(user_id: int, new_region_id) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.region_id = new_region_id
                return True
            return False


async def update_year_first(user_id: int, new_year_first: int) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.year_first = new_year_first
                return True
            return False


async def update_year_second(user_id: int, new_year_second: int) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.year_second = new_year_second
                return True
            return False


async def update_price_first(user_id: int, new_price_first: float) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.price_first = new_price_first
                return True
            return False


async def update_price_second(user_id: int, new_price_second: float) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.price_second = new_price_second
                return True
            return False


async def update_run_mode(user_id: int, run_mode: str) -> bool:
    mode = RUN_MODE_SCHEDULE if run_mode == RUN_MODE_SCHEDULE else RUN_MODE_MANUAL
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.run_mode = mode
                return True
            return False


async def update_work_from(user_id: int, work_from: str) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.work_from = format_hhmm(work_from, DEFAULT_WORK_FROM)
                return True
            return False


async def update_work_to(user_id: int, work_to: str) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.work_to = format_hhmm(work_to, DEFAULT_WORK_TO)
                return True
            return False


async def update_work_days(user_id: int, work_days) -> bool:
    days = normalize_work_days(work_days)
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if record:
                record.work_days = days
                return True
            return False


async def update_schedule(
    user_id: int,
    *,
    run_mode: str | None = None,
    work_from: str | None = None,
    work_to: str | None = None,
    work_days=None,
) -> bool:
    async with async_session() as session:
        async with session.begin():
            result = await session.execute(
                select(filtersettings).where(filtersettings.user_id == user_id)
            )
            record = result.scalars().first()
            if not record:
                return False
            if run_mode is not None:
                record.run_mode = (
                    RUN_MODE_SCHEDULE if run_mode == RUN_MODE_SCHEDULE else RUN_MODE_MANUAL
                )
            if work_from is not None:
                record.work_from = format_hhmm(work_from, DEFAULT_WORK_FROM)
            if work_to is not None:
                record.work_to = format_hhmm(work_to, DEFAULT_WORK_TO)
            if work_days is not None:
                record.work_days = normalize_work_days(work_days)
            return True


async def get_filter_settings(user_id: int) -> filtersettings | None:
    async with async_session() as session:
        result = await session.execute(
            select(filtersettings).where(filtersettings.user_id == user_id)
        )
        record = result.scalars().first()
        return record


async def get_filter_settings_dict(user_id: int) -> dict:
    record = await get_filter_settings(user_id)
    if record:
        return _record_to_dict(record)
    return {}


async def get_schedule_enabled_users() -> list[dict]:
    """Пользователи с режимом «по расписанию»."""
    async with async_session() as session:
        result = await session.execute(
            select(filtersettings).where(filtersettings.run_mode == RUN_MODE_SCHEDULE)
        )
        records = result.scalars().all()
        # Также подхватываем NULL/пустые как manual — только явный schedule
        return [_record_to_dict(r) for r in records]
