-- ============================================================
-- Migration 008: Schema Gap Backfill (Idempotent)
-- Date: 2026-02-15
-- Purpose:
-- 1) Patch common missing columns on legacy DBs
-- 2) Keep orders.qty and orders.quantity in sync
-- 3) Ensure trade lifecycle traceability fields exist
-- 4) Add bot_snapshots table for rolling bot_state backups
-- ============================================================

BEGIN;

-- ------------------------------------------------------------
-- A) trade_history compatibility
-- ------------------------------------------------------------
ALTER TABLE IF EXISTS trade_history
    ADD COLUMN IF NOT EXISTS trade_id text;

ALTER TABLE IF EXISTS trade_history
    ADD COLUMN IF NOT EXISTS source text;

-- Ensure source has valid values and no nulls.
UPDATE trade_history
SET source = CASE
    WHEN upper(coalesce(source, '')) IN ('BOT', 'MANUAL') THEN upper(source)
    WHEN profile_id IS NOT NULL THEN 'BOT'
    ELSE 'MANUAL'
END
WHERE source IS NULL
   OR btrim(source) = ''
   OR upper(source) NOT IN ('BOT', 'MANUAL');

ALTER TABLE IF EXISTS trade_history
    ALTER COLUMN source SET DEFAULT 'BOT';

ALTER TABLE IF EXISTS trade_history
    ALTER COLUMN source SET NOT NULL;

CREATE INDEX IF NOT EXISTS idx_trade_history_trade_id
    ON trade_history (trade_id);

CREATE INDEX IF NOT EXISTS idx_trade_history_source
    ON trade_history (source);

CREATE INDEX IF NOT EXISTS idx_trade_history_profile_trade_id_created
    ON trade_history (profile_id, trade_id, created_at DESC)
    WHERE trade_id IS NOT NULL;

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM pg_constraint
        WHERE conname = 'chk_trade_history_trade_id_not_blank'
          AND conrelid = 'trade_history'::regclass
    ) THEN
        ALTER TABLE trade_history
            ADD CONSTRAINT chk_trade_history_trade_id_not_blank
            CHECK (trade_id IS NULL OR btrim(trade_id) <> '')
            NOT VALID;
    END IF;
END $$;

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM pg_constraint
        WHERE conname = 'chk_trade_history_trade_id_format'
          AND conrelid = 'trade_history'::regclass
    ) THEN
        ALTER TABLE trade_history
            ADD CONSTRAINT chk_trade_history_trade_id_format
            CHECK (trade_id IS NULL OR trade_id LIKE 'TRD-%')
            NOT VALID;
    END IF;
END $$;

-- ------------------------------------------------------------
-- B) orders compatibility
-- ------------------------------------------------------------
ALTER TABLE IF EXISTS orders
    ADD COLUMN IF NOT EXISTS trade_id text;

ALTER TABLE IF EXISTS orders
    ADD COLUMN IF NOT EXISTS action text;

ALTER TABLE IF EXISTS orders
    ADD COLUMN IF NOT EXISTS source text;

ALTER TABLE IF EXISTS orders
    ADD COLUMN IF NOT EXISTS quantity numeric;

-- Source normalization.
UPDATE orders
SET source = CASE
    WHEN upper(coalesce(source, '')) IN ('BOT', 'MANUAL') THEN upper(source)
    WHEN profile_id IS NOT NULL THEN 'BOT'
    ELSE 'MANUAL'
END
WHERE source IS NULL
   OR btrim(source) = ''
   OR upper(source) NOT IN ('BOT', 'MANUAL');

ALTER TABLE IF EXISTS orders
    ALTER COLUMN source SET DEFAULT 'BOT';

ALTER TABLE IF EXISTS orders
    ALTER COLUMN source SET NOT NULL;

-- Keep qty/quantity aligned for legacy + current clients.
UPDATE orders
SET quantity = qty
WHERE quantity IS NULL
  AND qty IS NOT NULL;

UPDATE orders
SET qty = quantity
WHERE qty IS NULL
  AND quantity IS NOT NULL;

CREATE OR REPLACE FUNCTION sync_orders_qty_quantity()
RETURNS trigger AS $$
BEGIN
    IF NEW.qty IS NULL AND NEW.quantity IS NOT NULL THEN
        NEW.qty := NEW.quantity;
    ELSIF NEW.quantity IS NULL AND NEW.qty IS NOT NULL THEN
        NEW.quantity := NEW.qty;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trg_orders_sync_qty_quantity ON orders;

CREATE TRIGGER trg_orders_sync_qty_quantity
BEFORE INSERT OR UPDATE ON orders
FOR EACH ROW
EXECUTE FUNCTION sync_orders_qty_quantity();

CREATE INDEX IF NOT EXISTS idx_orders_trade_id
    ON orders (trade_id);

CREATE INDEX IF NOT EXISTS idx_orders_source
    ON orders (source);

CREATE INDEX IF NOT EXISTS idx_orders_profile_trade_id_created
    ON orders (profile_id, trade_id, created_at DESC)
    WHERE trade_id IS NOT NULL;

CREATE INDEX IF NOT EXISTS idx_orders_profile_trade_id_action_created
    ON orders (profile_id, trade_id, action, created_at DESC)
    WHERE trade_id IS NOT NULL;

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM pg_constraint
        WHERE conname = 'chk_orders_action_lifecycle'
          AND conrelid = 'orders'::regclass
    ) THEN
        ALTER TABLE orders
            ADD CONSTRAINT chk_orders_action_lifecycle
            CHECK (action IS NULL OR action IN ('ENTRY', 'EXIT'))
            NOT VALID;
    END IF;
END $$;

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM pg_constraint
        WHERE conname = 'chk_orders_trade_id_not_blank'
          AND conrelid = 'orders'::regclass
    ) THEN
        ALTER TABLE orders
            ADD CONSTRAINT chk_orders_trade_id_not_blank
            CHECK (trade_id IS NULL OR btrim(trade_id) <> '')
            NOT VALID;
    END IF;
END $$;

DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1
        FROM pg_constraint
        WHERE conname = 'chk_orders_trade_id_format'
          AND conrelid = 'orders'::regclass
    ) THEN
        ALTER TABLE orders
            ADD CONSTRAINT chk_orders_trade_id_format
            CHECK (trade_id IS NULL OR trade_id LIKE 'TRD-%')
            NOT VALID;
    END IF;
END $$;

-- ------------------------------------------------------------
-- C) bot_snapshots table for rolling state backups
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS bot_snapshots (
    id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
    state_json jsonb NOT NULL,
    created_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_bot_snapshots_user_created
    ON bot_snapshots (user_id, created_at DESC);

COMMIT;

-- ------------------------------------------------------------
-- Post-run checks (optional)
-- ------------------------------------------------------------
-- SELECT column_name FROM information_schema.columns
-- WHERE table_schema='public' AND table_name='orders'
--   AND column_name IN ('qty','quantity','trade_id','action','source');
--
-- SELECT column_name FROM information_schema.columns
-- WHERE table_schema='public' AND table_name='trade_history'
--   AND column_name IN ('trade_id','source');
--
-- SELECT count(*) AS snapshots FROM bot_snapshots;
