"""
Directors dashboard API - revenue totals (weekly, MTD, FYTD), cash in bank, time utilisation.
Requires directors.access permission.
Optional month (1-12) and year: when provided, MTD = that month, FYTD = July 1 to end of that month.
"""
import calendar
import os
from datetime import date, timedelta
from typing import Any, Dict, Optional

from fastapi import APIRouter, Depends, Query
from app.routers.auth import get_current_user, require_permission
from app.models import User
from app.config import settings
from app.services.time_utilisation_service import load_time_utilisation_by_branch
from app.services.wip_jobs_service import get_wip_jobs_all_branches
from app.services.simpro_quotes_service import get_quote_data_all_branches
from app.config.xero_config import is_xero_enabled
from app.services.kpi_sheets_service import kpi_sheets_service
import logging

logger = logging.getLogger(__name__)

try:
    from app.services.xero_service import xero_service
    XERO_AVAILABLE = True
except ImportError:
    XERO_AVAILABLE = False
    xero_service = None

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

# Branch ID -> display name for directors view
BRANCH_ORDER = [
    ("branch2", "Bunbury"),
    ("branch1", "Busselton"),
    ("branch3", "Mandurah"),
]


def _start_of_week(d: date) -> date:
    """Monday = start of week. Return the Monday on or before d."""
    days_since_monday = d.weekday()
    return d - timedelta(days=days_since_monday)


def _start_of_fy(d: date) -> date:
    """Australian FY: July 1 - June 30."""
    if d.month >= 7:
        return date(d.year, 7, 1)
    return date(d.year - 1, 7, 1)


def _last_day_of_month(y: int, m: int) -> date:
    """Last day of the given calendar month (1-12)."""
    _, last = calendar.monthrange(y, m)
    return date(y, m, last)


async def build_directors_payload(
    month: Optional[int] = None,
    year: Optional[int] = None,
    quote_from_date: Optional[date] = None,
    quote_to_date: Optional[date] = None,
) -> Dict[str, Any]:
    """
    Build the directors dashboard payload (same shape as GET /api/directors).
    Shared with admin custom-pages data API. Does not perform auth.
    Optional month (1-12) and year: when both provided, MTD = that calendar month,
    FYTD = from start of FY (July 1) to end of that month. Otherwise uses today.
    """
    today = date.today()
    use_month_year = month is not None and year is not None and 1 <= month <= 12
    if use_month_year:
        try:
            period_end = _last_day_of_month(year, month)
            mtd_start = date(year, month, 1)
            mtd_end = period_end
            fy_start = _start_of_fy(period_end)
            fytd_end = period_end
        except (ValueError, TypeError):
            use_month_year = False

    if not use_month_year:
        month = today.month
        year = today.year
        period_end = today
        mtd_start = date(today.year, today.month, 1)
        mtd_end = today
        fy_start = _start_of_fy(today)
        fytd_end = today

    week_start = _start_of_week(period_end)

    cash_taken = {}
    cash_in_bank = {}
    branch_financials = {}
    _empty_fin = {"revenue": 0.0, "gross_profit": 0.0, "gp_pct": 0.0, "net_profit": 0.0, "np_pct": 0.0}

    for branch_id, branch_name in BRANCH_ORDER:
        if branch_id not in settings.BRANCHES:
            continue
        branch_data = {}
        if XERO_AVAILABLE and is_xero_enabled(branch_id):
            try:
                branch_data["thisWeek"] = xero_service.get_revenue_for_date_range(
                    week_start, period_end, branch_id
                )
                mtd_fin = xero_service.get_branch_financials_for_date_range(
                    mtd_start, mtd_end, branch_id
                )
                fytd_fin = xero_service.get_branch_financials_for_date_range(
                    fy_start, fytd_end, branch_id
                )
                branch_data["mtd"] = mtd_fin.get("revenue", 0.0)
                branch_data["fytd"] = fytd_fin.get("revenue", 0.0)
                branch_financials[branch_name] = {"mtd": mtd_fin, "fytd": fytd_fin}
            except Exception as e:
                logger.warning(f"Error fetching revenue for {branch_name}: {e}")
                branch_data = {"thisWeek": 0.0, "mtd": 0.0, "fytd": 0.0}
                branch_financials[branch_name] = {"mtd": dict(_empty_fin), "fytd": dict(_empty_fin)}
        else:
            branch_data = {"thisWeek": 0.0, "mtd": 0.0, "fytd": 0.0}
            branch_financials[branch_name] = {"mtd": dict(_empty_fin), "fytd": dict(_empty_fin)}
        cash_taken[branch_name] = branch_data

        # Cash in bank (Balance Sheet report – statement balance for same 3 accounts on all branches)
        if XERO_AVAILABLE and is_xero_enabled(branch_id):
            try:
                balance = xero_service.get_cash_in_bank(branch_id)
                cash_in_bank[f"Nixon {branch_name}"] = balance if balance is not None else 0.0
            except Exception as e:
                logger.warning(f"Error fetching cash in bank for {branch_name}: {e}", exc_info=True)
                cash_in_bank[f"Nixon {branch_name}"] = 0.0
        else:
            cash_in_bank[f"Nixon {branch_name}"] = 0.0

    # Nixon Management and Nixon Assets - separate Xero tenants (financials + cash in bank)
    for entity_key, (entity_name, tenant_id_env) in [
        ("Nixon Management", ("Nixon Management (WA) Pty Ltd", "XERO_MANAGEMENT_TENANT_ID")),
        ("Nixon Assets", ("Nixon Assets (WA) Pty Ltd", "XERO_ASSETS_TENANT_ID")),
    ]:
        tenant_id = os.getenv(tenant_id_env)
        if tenant_id and tenant_id.strip():
            try:
                balance = xero_service.get_cash_in_bank_by_tenant_id(tenant_id)
                cash_in_bank[entity_key] = balance if balance is not None else 0.0
            except Exception as e:
                logger.warning(f"Error fetching cash in bank for {entity_key}: {e}", exc_info=True)
                cash_in_bank[entity_key] = 0.0
            try:
                mtd_fin = xero_service.get_financials_for_tenant_id(mtd_start, mtd_end, tenant_id)
                fytd_fin = xero_service.get_financials_for_tenant_id(fy_start, fytd_end, tenant_id)
                branch_financials[entity_key] = {"mtd": mtd_fin, "fytd": fytd_fin}
                cash_taken[entity_key] = {
                    "thisWeek": 0.0,
                    "mtd": mtd_fin.get("revenue", 0.0),
                    "fytd": fytd_fin.get("revenue", 0.0),
                }
            except Exception as e:
                logger.warning(f"Error fetching financials for {entity_key}: {e}", exc_info=True)
                branch_financials[entity_key] = {"mtd": dict(_empty_fin), "fytd": dict(_empty_fin)}
                cash_taken[entity_key] = {"thisWeek": 0.0, "mtd": 0.0, "fytd": 0.0}
        else:
            cash_in_bank[entity_key] = None  # Not configured
            branch_financials[entity_key] = {"mtd": dict(_empty_fin), "fytd": dict(_empty_fin)}
            cash_taken[entity_key] = {"thisWeek": 0.0, "mtd": 0.0, "fytd": 0.0}

    # Time utilisation - from CSV (Weekly Time Utilisation per branch)
    time_utilisation = load_time_utilisation_by_branch()

    # WIP jobs — Simpro API only (per branch, cached)
    wip_jobs = await get_wip_jobs_all_branches()

    # Quote data — Simpro API (DateIssued in range), cohort matches dashboard month unless from_date/to_date override
    q_from, q_to = mtd_start, mtd_end
    if quote_from_date is not None and quote_to_date is not None:
        q_from = quote_from_date
        q_to = quote_to_date
    quote_data = await get_quote_data_all_branches(q_from, q_to)

    # Subscriber totals - from Google Sheets "Subscriber Totals" tab
    subscriber_totals = _get_subscriber_totals()

    # First/last day of selected month for frontend (time utilisation filter, cash/oe/sr month names)
    filter_from_date = mtd_start.isoformat() if use_month_year else None
    filter_to_date = mtd_end.isoformat() if use_month_year else None

    return {
        "cash_taken": cash_taken,
        "cash_in_bank": cash_in_bank,
        "branch_financials": branch_financials,
        "time_utilisation": time_utilisation,
        "wip_jobs": wip_jobs,
        "quote_data": quote_data,
        "subscriber_totals": subscriber_totals,
        "date_filter_applied": use_month_year,
        "filter_month": month,
        "filter_year": year,
        "filter_from_date": filter_from_date,
        "filter_to_date": filter_to_date,
    }


@router.get("")
async def get_directors_data(
    user: User = Depends(require_permission("directors.access")),
    month: Optional[int] = None,
    year: Optional[int] = None,
    from_date: Optional[date] = Query(None, description="Quote cohort start (YYYY-MM-DD), requires to_date"),
    to_date: Optional[date] = Query(None, description="Quote cohort end (YYYY-MM-DD), requires from_date"),
):
    """
    Get directors dashboard data: revenue (MTD, FYTD), cash in bank, time utilisation.
    Optional month (1-12) and year: when both provided, MTD = that calendar month,
    FYTD = from start of FY (July 1) to end of that month. Otherwise uses today.
    Optional from_date + to_date: restrict Simpro quote metrics to that inclusive range (Perth calendar dates).
    """
    q_from = from_date if from_date is not None and to_date is not None else None
    q_to = to_date if from_date is not None and to_date is not None else None
    return await build_directors_payload(month=month, year=year, quote_from_date=q_from, quote_to_date=q_to)


def _get_subscriber_totals():
    """Fetch annual subscription counts from Subscriber Totals tab (A2=Busselton, A4=Bunbury, A6=Mandurah)."""
    try:
        return kpi_sheets_service.get_subscriber_totals()
    except Exception as e:
        logger.warning(f"Could not fetch subscriber totals: {e}")
        return {"Busselton": 0, "Bunbury": 0, "Mandurah": 0}


