"""Top-level control export orchestration."""

from __future__ import annotations

import logging

import asyncpg

from services.control.inverter import write_inverter_setpoints
from services.control.models import ControlSetpoints
from services.control.outputs import (
    send_loxone_setpoints,
    write_ev_setpoints,
    write_heat_pump_setpoint,
)
from services.control.repository import (
    _fetch_max_charge_power_w,
    _fetch_operating_mode,
    _fetch_plan_row_for_slot_offset,
    _load_inverter_config,
)
from services.control.setpoints import (
    _apply_export_plan_guard,
    _apply_price_failsafe_guard,
    _build_setpoints,
)
from services.signal_service import enqueue_site_signals

logger = logging.getLogger(__name__)


async def export_setpoints(site_id: int, db: asyncpg.Connection) -> None:
    mode = await _fetch_operating_mode(site_id, db)
    if mode is None:
        logger.warning("control export site=%s: no operating mode row", site_id)
        return

    if mode.mode_code == "MANUAL":
        logger.info("control export site=%s: MANUAL, skip writes", site_id)
        return

    try:
        inv_for_pv = await _load_inverter_config(site_id, db)
        cap_pv = int(inv_for_pv.pv_a_cap_w) if inv_for_pv is not None else 0
        min_pv = int(inv_for_pv.pv_a_reg340_min_w) if inv_for_pv is not None else 0
        reg340_en = (
            bool(inv_for_pv.deye_reg340_pv_a_control_enabled)
            if inv_for_pv is not None
            else False
        )
        pi_now = await _fetch_plan_row_for_slot_offset(site_id, db, 0)
        pi_next = await _fetch_plan_row_for_slot_offset(site_id, db, 1)
        sp_now = _build_setpoints(
            mode,
            pi_now,
            pv_a_cap_w=cap_pv,
            pv_a_reg340_min_w=min_pv,
            reg340_pv_a_control_enabled=reg340_en,
        )
        sp_next = _build_setpoints(
            mode,
            pi_next,
            pv_a_cap_w=cap_pv,
            pv_a_reg340_min_w=min_pv,
            reg340_pv_a_control_enabled=reg340_en,
        )

        if mode.mode_code == "AUTO" and sp_now is None:
            if pi_now is None:
                logger.warning(
                    "control export site=%s: AUTO but no planning_interval for current slot, skip",
                    site_id,
                )
            return

        if sp_now is None:
            logger.warning(
                "control export site=%s: no setpoints for mode %s, skip",
                site_id,
                mode.mode_code,
            )
            return

        if mode.mode_code == "CHARGE_CHEAP":
            max_ch = await _fetch_max_charge_power_w(site_id, db)
            pw = max(1, int(max_ch))
            sp_now = ControlSetpoints(
                battery_w=pw,
                grid_export_limit=0,
                ev1_current_a=0,
                ev2_current_a=0,
                heat_pump_enable=False,
                grid_setpoint_w=pw,
                ev1_power_w=0,
                ev2_power_w=0,
                target_soc_pct=None,
                effective_sell_price_czk_kwh=None,
            )
            sp_next = sp_now
        else:
            sp_now = _apply_export_plan_guard(site_id, mode, pi_now, sp_now)
            sp_now = _apply_price_failsafe_guard(site_id, mode, pi_now, sp_now)
            if sp_next is not None:
                sp_next = _apply_export_plan_guard(site_id, mode, pi_next, sp_next)
                sp_next = _apply_price_failsafe_guard(site_id, mode, pi_next, sp_next)

        planning_run_id = await db.fetchval(
            """
            SELECT id FROM ems.planning_run
            WHERE site_id = $1 AND status = 'active'
            ORDER BY created_at DESC
            LIMIT 1
            """,
            site_id,
        )
        if planning_run_id is not None:
            planning_run_id = int(planning_run_id)

        try:
            inv_res = await write_inverter_setpoints(
                site_id, sp_now, sp_next, db, planning_run_id=planning_run_id
            )
        except Exception as e:
            logger.error("inverter write failed: %s", e)
            inv_res = f"FAIL inverter: {e}"

        try:
            ev_res = await write_ev_setpoints(site_id, sp_now, db)
        except Exception as e:
            logger.error("ev write failed: %s", e)
            ev_res = f"FAIL ev: {e}"

        try:
            hp_res = await write_heat_pump_setpoint(site_id, sp_now, db)
        except Exception as e:
            logger.error("hp write failed: %s", e)
            hp_res = f"FAIL heat pump: {e}"

        try:
            lox_res = await send_loxone_setpoints(site_id, sp_now, mode, db)
        except Exception as e:
            logger.error("loxone write failed: %s", e)
            lox_res = f"FAIL Loxone: {e}"

        results = list(
            zip(
                ("inverter", "ev", "heat_pump", "loxone"),
                (inv_res, ev_res, hp_res, lox_res),
            )
        )

        for name, res in results:
            if isinstance(res, Exception):
                logger.error("control export site=%s %s: FAIL %s", site_id, name, res)
            elif isinstance(res, str) and res.startswith("FAIL"):
                logger.error("control export site=%s %s: %s", site_id, name, res)
            else:
                logger.info("control export site=%s %s: %s", site_id, name, res)
    finally:
        try:
            await enqueue_site_signals(site_id, db)
        except Exception as e:
            logger.warning(
                "control export site=%s: signal enqueue failed: %s", site_id, e
            )
