from fastapi import APIRouter, Query

from backend.db.database import get_connection
from backend.services.settings_service import get_income_settings, get_exclude_transfers

router = APIRouter(prefix="/api/charts", tags=["charts"])


def _parse_bank_ids(bank_ids: str | None) -> list[int] | None:
    if not bank_ids or not bank_ids.strip():
        return None
    try:
        return [int(x.strip()) for x in bank_ids.split(",") if x.strip()]
    except ValueError:
        return None


@router.get("/income-expense")
def income_expense_by_month(
    year: int | None = Query(None),
    period_start: str | None = Query(None),
    period_end: str | None = Query(None),
    bank_ids: str | None = Query(None),
):
    """Доход и расход по месяцам. Фильтры: year или period_start/period_end, bank_ids."""
    conn = get_connection()
    try:
        salary_id = conn.execute("SELECT id FROM banks WHERE is_salary = 1").fetchone()
        salary_id = salary_id["id"] if salary_id else None
        only_salary_card, salary_account_id = get_income_settings()
        exclude_filter = " AND (t.excluded_from_balance = 0 OR t.excluded_from_balance IS NULL)"
        if get_exclude_transfers():
            exclude_filter += " AND t.description NOT LIKE '%Перевод%'"
        bank_id_list = _parse_bank_ids(bank_ids)
        bank_filter = ""
        params = []
        if bank_id_list:
            placeholders = ",".join("?" * len(bank_id_list))
            bank_filter = f" AND a.bank_id IN ({placeholders})"
            params = list(bank_id_list)
        date_filter = ""
        if year is not None:
            date_filter = " AND strftime('%Y', t.operation_date) = ?"
            params = [str(year)] + params
        elif period_start or period_end:
            if period_start:
                date_filter += " AND t.operation_date >= ?"
                params.append(period_start)
            if period_end:
                date_filter += " AND t.operation_date <= ?"
                params.append(period_end)
        rows = conn.execute("""
            SELECT strftime('%Y-%m', t.operation_date) as month,
                   SUM(CASE WHEN t.amount > 0 THEN t.amount ELSE 0 END) as debit,
                   SUM(CASE WHEN t.amount < 0 THEN -t.amount ELSE 0 END) as credit,
                   a.bank_id, a.id as account_id
            FROM transactions t
            JOIN accounts a ON t.account_id = a.id
            WHERE 1=1
            """ + exclude_filter + bank_filter + date_filter + """
            GROUP BY month, a.bank_id, a.id
            ORDER BY month
        """, params).fetchall()

        # Агрегируем по месяцам; доход — по зарплатному банку или только по выбранной карте
        by_month = {}
        for r in rows:
            m = r["month"]
            if m not in by_month:
                by_month[m] = {"month": m, "debit": 0.0, "credit": 0.0, "income": 0.0}
            by_month[m]["debit"] += r["debit"]
            by_month[m]["credit"] += r["credit"]
            if only_salary_card and salary_account_id and r["account_id"] == salary_account_id:
                by_month[m]["income"] += r["debit"]
            elif not only_salary_card and salary_id and r["bank_id"] == salary_id:
                by_month[m]["income"] += r["debit"]

        return list(by_month.values())
    finally:
        conn.close()


@router.get("/balance-dynamics")
def balance_dynamics(
    period_start: str | None = Query(None),
    period_end: str | None = Query(None),
    bank_ids: str | None = Query(None),
):
    """Суммарный остаток на конец каждого дня (накопленно). bank_ids — фильтр по банкам."""
    conn = get_connection()
    try:
        bank_id_list = _parse_bank_ids(bank_ids)
        if bank_id_list:
            placeholders = ",".join("?" * len(bank_id_list))
            acc_filter = f" AND account_id IN (SELECT id FROM accounts WHERE bank_id IN ({placeholders}))"
            params = list(bank_id_list)
        else:
            acc_filter = ""
            params = []
        transfer_filter = " AND description NOT LIKE '%Перевод%'" if get_exclude_transfers() else ""
        sql = """
            SELECT date(operation_date) as day, SUM(amount) as daily_total
            FROM transactions
            WHERE (excluded_from_balance = 0 OR excluded_from_balance IS NULL)
        """ + transfer_filter + acc_filter
        if period_start:
            sql += " AND operation_date >= ?"
            params.append(period_start)
        if period_end:
            sql += " AND operation_date <= ?"
            params.append(period_end)
        sql += " GROUP BY day ORDER BY day"
        rows = conn.execute(sql, params).fetchall()
        # Накопленный итог
        cumul = 0.0
        result = []
        for r in rows:
            cumul += r["daily_total"]
            result.append({"date": r["day"], "balance": round(cumul, 2)})
        return result
    finally:
        conn.close()


@router.get("/savings-dynamics")
def savings_dynamics(
    period_start: str | None = Query(None),
    period_end: str | None = Query(None),
    bank_ids: str | None = Query(None),
):
    """Динамика копилки: накопленная сумма операций «Перевод между счетами одного клиента» по дням."""
    conn = get_connection()
    try:
        bank_id_list = _parse_bank_ids(bank_ids)
        if bank_id_list:
            placeholders = ",".join("?" * len(bank_id_list))
            acc_filter = f" AND account_id IN (SELECT id FROM accounts WHERE bank_id IN ({placeholders}))"
            params = ["%Перевод между счетами одного клиента%"] + list(bank_id_list)
        else:
            acc_filter = ""
            params = ["%Перевод между счетами одного клиента%"]
        transfer_filter = " AND description NOT LIKE '%Перевод%'" if get_exclude_transfers() else ""
        sql = """
            SELECT date(operation_date) as day, SUM(-amount) as daily_savings
            FROM transactions
            WHERE description LIKE ?
              AND (excluded_from_balance = 0 OR excluded_from_balance IS NULL)
        """ + transfer_filter + acc_filter
        if period_start:
            sql += " AND operation_date >= ?"
            params.append(period_start)
        if period_end:
            sql += " AND operation_date <= ?"
            params.append(period_end)
        sql += " GROUP BY day ORDER BY day"
        rows = conn.execute(sql, params).fetchall()
        cumul = 0.0
        result = []
        for r in rows:
            cumul += r["daily_savings"]
            result.append({"date": r["day"], "savings": round(cumul, 2)})
        return result
    finally:
        conn.close()
