-- =============================================================
-- R__fn_set_mode.sql
-- EMS Platform – přepínání provozních režimů
-- Repeatable migration
-- =============================================================

CREATE OR REPLACE FUNCTION ems.fn_set_mode(
    p_site_id    INT,
    p_mode_code  TEXT,
    p_activated_by TEXT DEFAULT 'system',
    p_valid_until  TIMESTAMPTZ DEFAULT NULL,
    p_notes        TEXT DEFAULT NULL
)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
    v_current_mode TEXT;
    v_mode_exists  BOOLEAN;
BEGIN
    -- Ověřit že režim existuje
    SELECT EXISTS(SELECT 1 FROM ems.operating_mode_def WHERE code = p_mode_code)
    INTO v_mode_exists;

    IF NOT v_mode_exists THEN
        RAISE EXCEPTION 'Neznámý provozní režim: %', p_mode_code;
    END IF;

    -- Zjistit aktuální režim (pro log a previous_mode)
    SELECT mode_code INTO v_current_mode
    FROM ems.site_operating_mode
    WHERE site_id = p_site_id;

    -- Pokud se režim nemění, nic nedělat
    IF v_current_mode = p_mode_code THEN
        RETURN p_mode_code;
    END IF;

    -- Uzavřít předchozí záznam v logu
    UPDATE ems.site_operating_mode_log
    SET deactivated_at = now()
    WHERE site_id = p_site_id
      AND deactivated_at IS NULL;

    -- Upsert aktivního režimu
    INSERT INTO ems.site_operating_mode
        (site_id, mode_code, activated_at, activated_by, valid_until, previous_mode, notes)
    VALUES
        (p_site_id, p_mode_code, now(), p_activated_by, p_valid_until, v_current_mode, p_notes)
    ON CONFLICT (site_id) DO UPDATE SET
        mode_code     = EXCLUDED.mode_code,
        activated_at  = EXCLUDED.activated_at,
        activated_by  = EXCLUDED.activated_by,
        valid_until   = EXCLUDED.valid_until,
        previous_mode = EXCLUDED.previous_mode,
        notes         = EXCLUDED.notes;

    -- Přidat záznam do logu
    INSERT INTO ems.site_operating_mode_log
        (site_id, mode_code, activated_at, activated_by, notes)
    VALUES
        (p_site_id, p_mode_code, now(), p_activated_by, p_notes);

    RETURN p_mode_code;
END;
$$;

COMMENT ON FUNCTION ems.fn_set_mode(INT, TEXT, TEXT, TIMESTAMPTZ, TEXT) IS
'Přepne provozní režim lokality. Atomicky aktualizuje site_operating_mode a zapíše do audit logu.
Ignoruje přepnutí na stejný režim. Vyhodí výjimku pro neznámý kód režimu.
Příklad: SELECT ems.fn_set_mode(1, ''SELF_SUSTAIN'', ''user:jan'', NULL, ''Odjezd na dovolenou'');';

-- ============================================================

CREATE OR REPLACE FUNCTION ems.fn_restore_previous_mode(
    p_site_id      INT,
    p_activated_by TEXT DEFAULT 'system'
)
RETURNS TEXT
LANGUAGE plpgsql
AS $$
DECLARE
    v_previous TEXT;
BEGIN
    SELECT previous_mode INTO v_previous
    FROM ems.site_operating_mode
    WHERE site_id = p_site_id;

    IF v_previous IS NULL THEN
        -- Fallback na AUTO pokud není předchozí režim
        v_previous := 'AUTO';
    END IF;

    RETURN ems.fn_set_mode(p_site_id, v_previous, p_activated_by, NULL, 'Obnova předchozího režimu');
END;
$$;

COMMENT ON FUNCTION ems.fn_restore_previous_mode(INT, TEXT) IS
'Přepne lokalitu zpět na předchozí provozní režim (uložený v previous_mode).
Pokud předchozí režim neexistuje, přepne na AUTO. Používat po skončení dočasného přepisu.';

-- ============================================================

CREATE OR REPLACE FUNCTION ems.fn_expire_modes()
RETURNS INT
LANGUAGE plpgsql
AS $$
DECLARE
    v_count INT := 0;
    v_rec   RECORD;
BEGIN
    -- Najít lokality kde vypršel valid_until a přepnout na AUTO
    FOR v_rec IN
        SELECT site_id, previous_mode
        FROM ems.site_operating_mode
        WHERE valid_until IS NOT NULL
          AND valid_until <= now()
          AND mode_code <> 'AUTO'
    LOOP
        PERFORM ems.fn_set_mode(
            v_rec.site_id,
            COALESCE(v_rec.previous_mode, 'AUTO'),
            'system:expiry',
            NULL,
            'Automatické vypršení dočasného režimu'
        );
        v_count := v_count + 1;
    END LOOP;

    RETURN v_count;
END;
$$;

COMMENT ON FUNCTION ems.fn_expire_modes() IS
'Zkontroluje všechny lokality s dočasným režimem (valid_until IS NOT NULL) a přepne zpět ty s prosahlým časem.
Volat každou minutu jako scheduled task. Vrátí počet přepnutých lokalit.';

-- ============================================================

CREATE OR REPLACE FUNCTION ems.fn_update_heartbeat(
    p_site_id    INT,
    p_status     TEXT DEFAULT 'ok',
    p_ems_version TEXT DEFAULT NULL
)
RETURNS VOID
LANGUAGE sql
AS $$
    INSERT INTO ems.site_heartbeat (site_id, last_seen, status, ems_version)
    VALUES (p_site_id, now(), p_status, p_ems_version)
    ON CONFLICT (site_id) DO UPDATE SET
        last_seen   = now(),
        status      = EXCLUDED.status,
        ems_version = COALESCE(EXCLUDED.ems_version, ems.site_heartbeat.ems_version);
$$;

COMMENT ON FUNCTION ems.fn_update_heartbeat(INT, TEXT, TEXT) IS
'Aktualizuje informační heartbeat záznam EMS pro danou lokalitu.
Volat každou minutu z backend service po úspěšném odeslání pulzu do Loxone.
Slouží pouze pro EMS dashboard – Loxone watchdog nezávisí na této tabulce,
sleduje HTTP pulzy přímo a nezávisle na dostupnosti DB.';
