# app/blueprints/planfix/routes.py

import math
from datetime import datetime

import pytz
from croniter import croniter
from flask import (
    Blueprint, render_template, redirect,
    url_for, flash, request, current_app,
)
from flask_login import login_required

from app.forms import PlanfixSettingsForm
from app.models.planfix_models import (
    PlanfixToken, PlanfixFetchLog, PlanfixCompany,
)
from app.extensions import db, scheduler
from app.security.rbac import role_required
from app.services.planfix_jobs import (
    reschedule_job, fetch_contracts, _do_test,
)

planfix_bp = Blueprint("planfix_bp", __name__, url_prefix="/admin/planfix")

# Локальная таймзона
PLANFIX_TZ = pytz.timezone("Europe/Kyiv")
PER_PAGE   = 20


def _paginate(query):
    """
    Простая пагинация: из SQLAlchemy-query возвращаем (items, page, pages).
    """
    page = request.args.get("page", 1, type=int)
    total = query.count()
    pages = math.ceil(total / PER_PAGE) or 1
    items = (
        query.order_by(PlanfixCompany.name.asc())
             .offset((page - 1) * PER_PAGE)
             .limit(PER_PAGE)
             .all()
    )
    return items, page, pages


@planfix_bp.route("/", methods=["GET", "POST"])
@login_required
@role_required("admin")
def settings():
    """
    Маршрут /admin/planfix/ — форма настроек, тест подключения, запуск “сейчас”,
    а также отображение журнала запусков и списка компаний (с поиском).
    """
    # 1) Берём единственный токен из БД (либо None)
    token: PlanfixToken | None = PlanfixToken.query.first()
    form  = PlanfixSettingsForm(obj=token)

    # ──────────────── СОХРАНЕНИЕ НАСТРОЕК ────────────────
    if form.submit_save.data and form.validate():
        # Если токена ещё нет — создаём новую запись
        if token is None:
            token = PlanfixToken()
            db.session.add(token)

        # Пишем только те поля, что ввёл пользователь
        if form.api_login.data is not None:
            token.api_login = form.api_login.data.strip()
        if form.api_token.data:
            token.api_token = form.api_token.data.strip()

        # Пересчёт cron-строки по выбранному времени
        rt = form.run_time.data
        token.cron_expr = f"{rt.minute} {rt.hour} * * *"

        db.session.commit()

        # Всегда пересоздаём задачу APScheduler (передаём реальный Flask-app)
        real_app = current_app._get_current_object()
        reschedule_job(token, app=real_app)

        flash("Налаштування збережено ✔", "success")
        return redirect(url_for(".settings"))

    # ──────────────── ТЕСТ СОЕДИНЕНИЯ ────────────────
    if form.submit_test.data:
        ok, msg = _do_test(
            form.api_login.data or (token.api_login if token else ""),
            form.api_token.data or (token.api_token if token else "")
        )
        flash(msg, "success" if ok else "danger")

    # ──────────────── ЗАПУСК “СЕЙЧАС” ────────────────
    if form.submit_run.data and token:
        fetch_contracts(app=current_app._get_current_object())
        flash("Запуск виконано", "info")
        return redirect(url_for(".settings"))

    # ──────────────── ПОДГОТОВКА ДАННЫХ ДЛЯ РЕНДЕРА ────────────────

    # 1) Журнал запусков APScheduler
    job  = scheduler.get_job("planfix_fetch")
    logs = (
        PlanfixFetchLog.query
        .order_by(PlanfixFetchLog.id.desc())
        .limit(30)
        .all()
    )

    # Последний запуск (UTC → локальная TZ)
    last_run = logs[0].run_at.astimezone(PLANFIX_TZ) if logs else None

    # Следующий запуск (если задача активна, берём из job.next_run_time;
    # иначе формируем “гипотетический” next_run по cron_expr)
    next_run = None
    if job and job.next_run_time:
        next_run = job.next_run_time.astimezone(PLANFIX_TZ)
    elif token:
        base = datetime.now(PLANFIX_TZ)
        try:
            next_run = croniter(token.cron_expr, base).get_next(datetime)
        except Exception:
            next_run = None

    # ──────────────── ПОИСК ПО ДОГОВОРАМ ────────────────
    # Читаем GET-параметр "search" (строка, введённая пользователем)
    search_query = request.args.get("search", "").strip()

    # Формируем базовый запрос к таблице компаний
    companies_q = PlanfixCompany.query

    if search_query:
        # Если пользователь ввёл только цифры — ищем по точному PF ID
        if search_query.isdigit():
            companies_q = companies_q.filter(
                PlanfixCompany.pf_company_id == int(search_query)
            )
        else:
            # Иначе ищем по части названия (case-insensitive ilike)
            wildcard = f"%{search_query}%"
            companies_q = companies_q.filter(
                PlanfixCompany.name.ilike(wildcard)
            )
    # ─────────────────────────────────────────────────────

    # Пагинация “после” фильтра (если он есть)
    companies, page, pages = _paginate(companies_q)
    total_companies = companies_q.count()

    return render_template(
        "admin/planfix_settings.html",
        form=form,
        token=token,
        job=job,
        logs=logs,
        last_run=last_run,
        next_run=next_run,

        # вот эти параметры для таблицы компаний
        companies=companies,
        page=page,
        pages=pages,
        total_companies=total_companies,

        # передаём текущую строку поиска, чтобы подставить её в шаблон
        search_query=search_query,
    )


@planfix_bp.post("/toggle")
@login_required
@role_required("admin")
def toggle():
    """
    Переключатель ON/OFF интеграции PlanFix. Меняем is_enabled
    и сразу же перепланируем задачу APScheduler.
    """
    token = PlanfixToken.query.first()
    if token is None:
        flash("Спочатку збережіть налаштування інтеграції.", "warning")
        return redirect(url_for(".settings"))

    token.is_enabled = not token.is_enabled
    db.session.commit()

    real_app = current_app._get_current_object()
    reschedule_job(token, app=real_app)

    status_text = "увімкнено" if token.is_enabled else "вимкнено"
    flash(f"Інтеграцію {status_text}", "info")
    return redirect(url_for(".settings"))
