-- =============================================================
-- R__fn_effective_price.sql
-- EMS Platform – funkce pro výpočet efektivní ceny per site
-- Repeatable migration – nasazuje se při každé změně
-- =============================================================

CREATE OR REPLACE FUNCTION ems.fn_effective_buy_price(
    p_site_id        INT,
    p_interval_start TIMESTAMPTZ
)
RETURNS NUMERIC(10,6)
LANGUAGE plpgsql
STABLE
AS $$
DECLARE
    v_spot_price       NUMERIC;
    v_energy_czk       NUMERIC;
    v_dist_rate        NUMERIC;
    v_system_services  NUMERIC;
    v_ote_fee          NUMERIC;
    v_vat_rate         NUMERIC;
    v_buy_margin_fixed NUMERIC;
    v_buy_margin_pct   NUMERIC;
    v_buy_margin       NUMERIC;
    v_is_vt            BOOLEAN;
    v_local_time       TIME;
    v_dow              INT;
    v_hdo_code_id      INT;
    v_tariff_id        INT;
    v_rate_type        TEXT;
    v_purchase_mode    TEXT;
    v_fixed_nt         NUMERIC;
    v_fixed_vt_sur     NUMERIC;
BEGIN
    SELECT
        smc.purchase_pricing_mode,
        smc.buy_fixed_energy_nt_czk_kwh,
        smc.buy_fixed_vt_surcharge_czk_kwh,
        smc.buy_margin_fixed_czk,
        smc.buy_margin_percent,
        smc.system_services_czk_kwh,
        smc.ote_fee_czk_kwh,
        smc.hdo_code_id,
        smc.tariff_id,
        dt.vat_rate
    INTO
        v_purchase_mode,
        v_fixed_nt,
        v_fixed_vt_sur,
        v_buy_margin_fixed,
        v_buy_margin_pct,
        v_system_services,
        v_ote_fee,
        v_hdo_code_id,
        v_tariff_id,
        v_vat_rate
    FROM ems.site_market_config smc
    LEFT JOIN ems.distribution_tariff dt ON dt.id = smc.tariff_id
    WHERE smc.site_id = p_site_id
      AND smc.valid_from <= p_interval_start
      AND (smc.valid_to IS NULL OR smc.valid_to > p_interval_start)
    ORDER BY smc.valid_from DESC
    LIMIT 1;

    IF NOT FOUND THEN
        RETURN NULL;
    END IF;

    SELECT buy_raw_price_czk_kwh INTO v_spot_price
    FROM ems.market_interval_price
    WHERE market_source IN ('OTE_CZ', 'OTE_CZ_DAM')
      AND interval_start = p_interval_start
    LIMIT 1;

    v_local_time := (p_interval_start AT TIME ZONE 'Europe/Prague')::TIME;
    v_dow        := EXTRACT(DOW FROM p_interval_start AT TIME ZONE 'Europe/Prague');
    -- 0=neděle, 6=sobota

    IF v_hdo_code_id IS NOT NULL THEN
        SELECT EXISTS (
            SELECT 1
            FROM ems.hdo_code_window w
            WHERE w.hdo_code_id = v_hdo_code_id
              AND (
                w.day_type = 'all'
                OR (w.day_type = 'workday' AND v_dow BETWEEN 1 AND 5)
                OR (w.day_type = 'weekend' AND v_dow IN (0, 6))
              )
              AND w.rate_type = 'VT'
              AND v_local_time >= w.window_from
              AND v_local_time <  w.window_to
        ) INTO v_is_vt;
    ELSE
        v_is_vt := false;
    END IF;

    v_rate_type := CASE WHEN v_is_vt THEN 'VT' ELSE 'NT' END;

    IF v_tariff_id IS NOT NULL THEN
        SELECT price_czk_kwh INTO v_dist_rate
        FROM ems.distribution_tariff_rate
        WHERE tariff_id  = v_tariff_id
          AND rate_type  = v_rate_type
          AND valid_from <= p_interval_start::DATE
          AND (valid_to IS NULL OR valid_to > p_interval_start::DATE)
        ORDER BY valid_from DESC
        LIMIT 1;
    END IF;

    v_dist_rate       := COALESCE(v_dist_rate, 0);
    v_system_services := COALESCE(v_system_services, 0);
    v_ote_fee         := COALESCE(v_ote_fee, 0);
    v_buy_margin_fixed := COALESCE(v_buy_margin_fixed, 0);
    v_buy_margin_pct   := COALESCE(v_buy_margin_pct, 0);
    v_vat_rate        := COALESCE(v_vat_rate, 0.21);
    v_fixed_vt_sur    := COALESCE(v_fixed_vt_sur, 0);

    IF upper(trim(COALESCE(v_purchase_mode, ''))) = 'FIXED'
       AND v_fixed_nt IS NOT NULL THEN
        v_energy_czk := v_fixed_nt
            + CASE WHEN v_is_vt THEN v_fixed_vt_sur ELSE 0 END;
    ELSIF v_spot_price IS NULL THEN
        RETURN NULL;
    ELSE
        v_energy_czk := v_spot_price;
    END IF;

    v_buy_margin := v_buy_margin_fixed + (v_energy_czk * v_buy_margin_pct / 100.0);

    RETURN ROUND(
        (v_energy_czk + v_dist_rate + v_system_services + v_ote_fee + v_buy_margin)
        * (1 + v_vat_rate),
        6
    );
END;
$$;

COMMENT ON FUNCTION ems.fn_effective_buy_price(INT, TIMESTAMPTZ) IS
'Efektivní nákupní cena elektřiny Kč/kWh včetně DPH.
Režim spot: energie = OTE buy_raw + distribuce NT/VT (dle HDO) + systémové služby + OTE poplatek + marže (fix + % z energie).
Režim fixed: energie = buy_fixed_energy_nt_czk_kwh (+ buy_fixed_vt_surcharge_czk_kwh ve VT oknech dle HDO), pak stejné příplatky a DPH.
DPH aplikováno na celou částku.';

-- ------------------------------------------------------------

CREATE OR REPLACE FUNCTION ems.fn_effective_sell_price(
    p_site_id        INT,
    p_interval_start TIMESTAMPTZ
)
RETURNS NUMERIC(10,6)
LANGUAGE plpgsql
STABLE
AS $$
DECLARE
    v_spot_price         NUMERIC;
    v_sell_margin_fixed  NUMERIC;
    v_sell_margin_pct    NUMERIC;
BEGIN
    SELECT sell_margin_fixed_czk, sell_margin_percent
    INTO v_sell_margin_fixed, v_sell_margin_pct
    FROM ems.site_market_config
    WHERE site_id = p_site_id
      AND valid_from <= p_interval_start
      AND (valid_to IS NULL OR valid_to > p_interval_start)
    ORDER BY valid_from DESC
    LIMIT 1;

    IF NOT FOUND THEN
        RETURN NULL;
    END IF;

    SELECT sell_raw_price_czk_kwh INTO v_spot_price
    FROM ems.market_interval_price
    WHERE market_source IN ('OTE_CZ', 'OTE_CZ_DAM')
      AND interval_start = p_interval_start
    LIMIT 1;

    IF v_spot_price IS NULL THEN
        RETURN NULL;
    END IF;

    RETURN ROUND(
        v_spot_price
        + COALESCE(v_sell_margin_fixed, 0)
        + (v_spot_price * COALESCE(v_sell_margin_pct, 0) / 100.0),
        6
    );
END;
$$;

COMMENT ON FUNCTION ems.fn_effective_sell_price(INT, TIMESTAMPTZ) IS
'Efektivní prodejní cena elektřiny Kč/kWh bez DPH (neplátce DPH).
Složky: spot OTE + fixní/procentní prodejní marže (záporná = srážka).
Zelený bonus není součástí ceny – počítá se z výroby přes fn_green_bonus_revenue().
Záporná hodnota = platíme za export (záporné spotové ceny).';

-- ------------------------------------------------------------

CREATE OR REPLACE FUNCTION ems.fn_green_bonus_revenue(
    p_pv_array_id    INT,
    p_interval_start TIMESTAMPTZ,
    p_production_wh  NUMERIC
)
RETURNS NUMERIC
LANGUAGE plpgsql
STABLE
AS $$
DECLARE
    v_bonus_rate NUMERIC;
BEGIN
    SELECT green_bonus_czk_kwh INTO v_bonus_rate
    FROM ems.asset_pv_array
    WHERE id = p_pv_array_id
      AND green_bonus_czk_kwh IS NOT NULL
      AND green_bonus_valid_from <= p_interval_start::DATE
      AND (green_bonus_valid_to IS NULL
           OR green_bonus_valid_to > p_interval_start::DATE);

    IF v_bonus_rate IS NULL OR p_production_wh IS NULL OR p_production_wh <= 0 THEN
        RETURN 0;
    END IF;

    RETURN ROUND((p_production_wh / 1000.0) * v_bonus_rate, 6);
END;
$$;

COMMENT ON FUNCTION ems.fn_green_bonus_revenue(INT, TIMESTAMPTZ, NUMERIC) IS
'Příjem ze zeleného bonusu za výrobu FVE pole v daném intervalu.
Bonus plyne z celkové výroby bez ohledu na to kam energie šla
(interní spotřeba, baterie, EV, TČ i export do sítě).
Sazba se načítá dle platnosti (valid_from/valid_to) – ročně aktualizovatelné.
Vrátí 0 pokud pole nemá zelený bonus nebo výroba je nulová.
Použití: SELECT ems.fn_green_bonus_revenue(pv_array_id, interval_start, production_wh);';
