-- =============================================================================
-- Ultimate Investment Tool — Supabase Schema
-- Paste this entire file into Supabase SQL Editor and click Run.
-- =============================================================================

-- -----------------------------------------------------------------------------
-- 1. TABLES
-- -----------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS licenses (
    id              UUID        DEFAULT gen_random_uuid() PRIMARY KEY,
    license_key     TEXT        UNIQUE NOT NULL,
    hwid            TEXT,                          -- NULL until first activation
    tier            TEXT        NOT NULL DEFAULT 'monthly', -- 'weekly' | 'monthly' | 'lifetime'
    expiry_date     TIMESTAMPTZ,                   -- NULL = lifetime
    active          BOOLEAN     NOT NULL DEFAULT true,
    machines_allowed INTEGER    NOT NULL DEFAULT 1,
    notes           TEXT,                          -- customer name / order ref
    created_at      TIMESTAMPTZ DEFAULT NOW(),
    activated_at    TIMESTAMPTZ
);

CREATE TABLE IF NOT EXISTS app_versions (
    id              UUID        DEFAULT gen_random_uuid() PRIMARY KEY,
    version         TEXT        UNIQUE NOT NULL,   -- e.g. '1.0.1'
    gui_py_url      TEXT,                          -- Supabase Storage URL for screener_gui.py
    screener_py_url TEXT,                          -- Supabase Storage URL for stock_screener.py
    release_notes   TEXT,
    is_latest       BOOLEAN     NOT NULL DEFAULT true,
    released_at     TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS auth_log (
    id              UUID        DEFAULT gen_random_uuid() PRIMARY KEY,
    license_key     TEXT,
    hwid            TEXT,
    result          TEXT,                          -- 'valid' | 'invalid'
    reason          TEXT,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- Seed the initial version row so the updater has something to compare against.
INSERT INTO app_versions (version, is_latest, release_notes)
VALUES ('1.0.0', true, 'Initial release')
ON CONFLICT (version) DO NOTHING;

-- -----------------------------------------------------------------------------
-- 2. ROW LEVEL SECURITY — no direct table access for anon
-- -----------------------------------------------------------------------------

ALTER TABLE licenses     ENABLE ROW LEVEL SECURITY;
ALTER TABLE app_versions ENABLE ROW LEVEL SECURITY;
ALTER TABLE auth_log     ENABLE ROW LEVEL SECURITY;

-- No RLS policies = anon/authenticated cannot SELECT/INSERT/UPDATE/DELETE directly.
-- All access goes through SECURITY DEFINER functions below.

-- -----------------------------------------------------------------------------
-- 3. RPC: verify_license(p_key, p_hwid) → JSON
-- -----------------------------------------------------------------------------
-- Called by the app on every launch with the stored license key + machine HWID.
-- Handles: first-time HWID binding, expiry, disabled keys, HWID mismatch.
-- Returns: { valid, reason, tier, expiry_date }
-- -----------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION verify_license(p_key TEXT, p_hwid TEXT)
RETURNS JSON
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
    lic    RECORD;
BEGIN
    -- Look up the key
    SELECT * INTO lic FROM licenses WHERE license_key = p_key;

    IF NOT FOUND THEN
        INSERT INTO auth_log (license_key, hwid, result, reason)
        VALUES (p_key, p_hwid, 'invalid', 'key_not_found');
        RETURN json_build_object(
            'valid',  false,
            'reason', 'License key not found.'
        );
    END IF;

    -- Check disabled
    IF NOT lic.active THEN
        INSERT INTO auth_log (license_key, hwid, result, reason)
        VALUES (p_key, p_hwid, 'invalid', 'key_disabled');
        RETURN json_build_object(
            'valid',  false,
            'reason', 'This license has been disabled. Please contact support.'
        );
    END IF;

    -- Check expiry (NULL = lifetime, never expires)
    IF lic.expiry_date IS NOT NULL AND lic.expiry_date < NOW() THEN
        INSERT INTO auth_log (license_key, hwid, result, reason)
        VALUES (p_key, p_hwid, 'invalid', 'expired');
        RETURN json_build_object(
            'valid',  false,
            'reason', 'Your subscription has expired. Please renew to continue.'
        );
    END IF;

    -- HWID check
    IF lic.hwid IS NULL THEN
        -- First activation — bind this machine
        UPDATE licenses
        SET hwid = p_hwid, activated_at = NOW()
        WHERE license_key = p_key;
    ELSIF lic.hwid <> p_hwid THEN
        INSERT INTO auth_log (license_key, hwid, result, reason)
        VALUES (p_key, p_hwid, 'invalid', 'hwid_mismatch');
        RETURN json_build_object(
            'valid',  false,
            'reason', 'This license is registered to a different machine. Contact support to transfer.'
        );
    END IF;

    -- All checks passed
    INSERT INTO auth_log (license_key, hwid, result, reason)
    VALUES (p_key, p_hwid, 'valid', 'ok');

    RETURN json_build_object(
        'valid',       true,
        'reason',      'ok',
        'tier',        lic.tier,
        'expiry_date', lic.expiry_date
    );
END;
$$;

-- -----------------------------------------------------------------------------
-- 4. RPC: get_latest_version() → JSON
-- -----------------------------------------------------------------------------
-- Called by the updater after a successful license check.
-- Returns: { version, gui_py_url, screener_py_url, release_notes }
-- -----------------------------------------------------------------------------

CREATE OR REPLACE FUNCTION get_latest_version()
RETURNS JSON
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
    ver RECORD;
BEGIN
    SELECT * INTO ver
    FROM app_versions
    WHERE is_latest = true
    ORDER BY released_at DESC
    LIMIT 1;

    IF NOT FOUND THEN
        RETURN json_build_object('version', '1.0.0');
    END IF;

    RETURN json_build_object(
        'version',         ver.version,
        'gui_py_url',      ver.gui_py_url,
        'screener_py_url', ver.screener_py_url,
        'release_notes',   ver.release_notes
    );
END;
$$;

-- -----------------------------------------------------------------------------
-- 5. GRANTS — allow anon key to call the two RPC functions only
-- -----------------------------------------------------------------------------

GRANT EXECUTE ON FUNCTION verify_license(TEXT, TEXT) TO anon;
GRANT EXECUTE ON FUNCTION get_latest_version()        TO anon;
