-- Migration 013: v0.2.0 Sales Intelligence Engine
-- Adds: competitor_alerts, price_changes, image tracking, finder views, blog_posts_v2, forecast tables

-- ============================================================
-- IMAGE TRACKING (WS0)
-- ============================================================

-- Add image columns if not exist
DO $$ BEGIN
  ALTER TABLE transceivers ADD COLUMN IF NOT EXISTS image_url TEXT;
  ALTER TABLE transceivers ADD COLUMN IF NOT EXISTS image_r2_key TEXT;
  ALTER TABLE transceivers ADD COLUMN IF NOT EXISTS image_thumb_r2_key TEXT;
  ALTER TABLE transceivers ADD COLUMN IF NOT EXISTS image_scraped_at TIMESTAMPTZ;
  ALTER TABLE transceivers ADD COLUMN IF NOT EXISTS has_image BOOLEAN DEFAULT FALSE;
EXCEPTION WHEN duplicate_column THEN NULL;
END $$;

DO $$ BEGIN
  ALTER TABLE switches ADD COLUMN IF NOT EXISTS image_thumb_r2_key TEXT;
  ALTER TABLE switches ADD COLUMN IF NOT EXISTS has_image BOOLEAN DEFAULT FALSE;
EXCEPTION WHEN duplicate_column THEN NULL;
END $$;

CREATE INDEX IF NOT EXISTS idx_transceivers_has_image ON transceivers(has_image) WHERE has_image = false;

-- ============================================================
-- PRICE COVERAGE (WS0b)
-- ============================================================

-- View: products missing recent prices
CREATE OR REPLACE VIEW v_price_coverage AS
SELECT
  t.id,
  t.slug,
  t.form_factor,
  t.speed_gbps,
  t.reach_label,
  v.name AS vendor_name,
  (SELECT MAX(po.time) FROM price_observations po WHERE po.transceiver_id = t.id) AS last_price_at,
  (SELECT COUNT(*) FROM price_observations po WHERE po.transceiver_id = t.id AND po.time > NOW() - INTERVAL '7 days') AS recent_price_count,
  CASE
    WHEN (SELECT COUNT(*) FROM price_observations po WHERE po.transceiver_id = t.id AND po.time > NOW() - INTERVAL '7 days') > 0 THEN TRUE
    ELSE FALSE
  END AS has_recent_price
FROM transceivers t
LEFT JOIN vendors v ON t.vendor_id = v.id
ORDER BY has_recent_price ASC, t.speed_gbps DESC;

-- View: image coverage
CREATE OR REPLACE VIEW v_image_coverage AS
SELECT
  t.id,
  t.slug,
  t.form_factor,
  t.speed_gbps,
  t.image_url,
  t.image_r2_key,
  t.has_image,
  v.name AS vendor_name
FROM transceivers t
LEFT JOIN vendors v ON t.vendor_id = v.id
ORDER BY t.has_image ASC, t.speed_gbps DESC;

-- ============================================================
-- COMPETITOR INTELLIGENCE (WS4)
-- ============================================================

CREATE TABLE IF NOT EXISTS competitor_alerts (
  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  vendor_id     UUID REFERENCES vendors(id),
  transceiver_id UUID REFERENCES transceivers(id),

  alert_type    TEXT NOT NULL CHECK (alert_type IN (
    'new_product', 'price_drop', 'price_increase', 'out_of_stock',
    'back_in_stock', 'discontinued', 'new_vendor'
  )),
  severity      TEXT DEFAULT 'info' CHECK (severity IN ('critical', 'high', 'medium', 'low', 'info')),

  -- Price change details
  old_price     NUMERIC,
  new_price     NUMERIC,
  price_delta   NUMERIC,       -- absolute change
  price_pct     NUMERIC,       -- percentage change
  currency      TEXT DEFAULT 'USD',

  -- Product details
  part_number   TEXT,
  product_name  TEXT,
  form_factor   TEXT,
  speed_gbps    NUMERIC,
  source_url    TEXT,

  -- Status
  acknowledged  BOOLEAN DEFAULT FALSE,
  notes         TEXT,

  created_at    TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_competitor_alerts_type ON competitor_alerts(alert_type);
CREATE INDEX IF NOT EXISTS idx_competitor_alerts_vendor ON competitor_alerts(vendor_id);
CREATE INDEX IF NOT EXISTS idx_competitor_alerts_created ON competitor_alerts(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_competitor_alerts_unack ON competitor_alerts(acknowledged) WHERE acknowledged = FALSE;
CREATE INDEX IF NOT EXISTS idx_competitor_alerts_severity ON competitor_alerts(severity);

-- Price change history (deduplicated, one row per actual change)
CREATE TABLE IF NOT EXISTS price_changes (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  transceiver_id  UUID REFERENCES transceivers(id),
  vendor_id       UUID REFERENCES vendors(id),

  old_price       NUMERIC NOT NULL,
  new_price       NUMERIC NOT NULL,
  delta           NUMERIC NOT NULL,           -- new - old
  delta_pct       NUMERIC NOT NULL,           -- ((new-old)/old) * 100
  currency        TEXT DEFAULT 'USD',

  detected_at     TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_price_changes_transceiver ON price_changes(transceiver_id, detected_at DESC);
CREATE INDEX IF NOT EXISTS idx_price_changes_vendor ON price_changes(vendor_id, detected_at DESC);
CREATE INDEX IF NOT EXISTS idx_price_changes_detected ON price_changes(detected_at DESC);

-- ============================================================
-- FINDER: FLEXOPTIX PRODUCT MAPPING (WS1)
-- ============================================================

-- Map OEM part numbers to Flexoptix products
CREATE TABLE IF NOT EXISTS flexoptix_product_map (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  oem_part_number TEXT NOT NULL,
  oem_vendor      TEXT NOT NULL,
  flexoptix_sku   TEXT,
  flexoptix_url   TEXT,
  flexoptix_price_eur NUMERIC,
  form_factor     TEXT,
  speed_gbps      NUMERIC,
  reach_label     TEXT,
  fiber_type      TEXT,
  match_type      TEXT DEFAULT 'exact' CHECK (match_type IN ('exact', 'equivalent', 'compatible', 'suggested')),
  last_verified   TIMESTAMPTZ,
  created_at      TIMESTAMPTZ DEFAULT NOW(),
  updated_at      TIMESTAMPTZ DEFAULT NOW(),

  UNIQUE(oem_part_number, oem_vendor)
);

CREATE INDEX IF NOT EXISTS idx_flexoptix_map_oem ON flexoptix_product_map(oem_part_number);
CREATE INDEX IF NOT EXISTS idx_flexoptix_map_vendor ON flexoptix_product_map(oem_vendor);
CREATE INDEX IF NOT EXISTS idx_flexoptix_map_ff ON flexoptix_product_map(form_factor, speed_gbps);

-- Finder view: switch → compatible Flexoptix products
CREATE OR REPLACE VIEW v_switch_flexoptix_finder AS
SELECT
  sw.id AS switch_id,
  sw.model AS switch_model,
  sw.series AS switch_series,
  sv.name AS switch_vendor,
  c.status AS compat_status,
  c.firmware_min,
  c.notes AS compat_notes,
  t.id AS transceiver_id,
  t.slug AS transceiver_slug,
  t.form_factor,
  t.speed_gbps,
  t.reach_label,
  t.fiber_type,
  t.wavelengths,
  t.connector,
  t.image_url AS transceiver_image,
  fpm.flexoptix_sku,
  fpm.flexoptix_url,
  fpm.flexoptix_price_eur,
  fpm.match_type,
  (SELECT po.price FROM price_observations po WHERE po.transceiver_id = t.id ORDER BY po.time DESC LIMIT 1) AS latest_price,
  (SELECT po.currency FROM price_observations po WHERE po.transceiver_id = t.id ORDER BY po.time DESC LIMIT 1) AS latest_currency
FROM switches sw
JOIN vendors sv ON sw.vendor_id = sv.id
JOIN compatibility c ON c.switch_id = sw.id AND c.status = 'compatible'
JOIN transceivers t ON c.transceiver_id = t.id
LEFT JOIN flexoptix_product_map fpm ON (
  fpm.form_factor = t.form_factor
  AND fpm.speed_gbps = t.speed_gbps
  AND fpm.reach_label = t.reach_label
);

-- ============================================================
-- BLOG ENGINE v2 (WS8)
-- ============================================================

CREATE TABLE IF NOT EXISTS blog_series (
  id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  title         TEXT NOT NULL,
  slug          TEXT NOT NULL UNIQUE,
  description   TEXT,
  total_parts   INTEGER DEFAULT 1,
  status        TEXT DEFAULT 'active' CHECK (status IN ('active', 'completed', 'paused')),
  created_at    TIMESTAMPTZ DEFAULT NOW()
);

-- Add v2 columns to existing blog_drafts if they exist
DO $$ BEGIN
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS series_id UUID REFERENCES blog_series(id);
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS series_part INTEGER;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS seo_title TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS seo_description TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS seo_slug TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS seo_focus_keyword TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS seo_score INTEGER;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS readability_score NUMERIC;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS hero_image_url TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS hero_image_r2_key TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS related_products UUID[];
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS related_switches UUID[];
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS competitor_data JSONB;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS pricing_data JSONB;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS export_markdown TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS export_html TEXT;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS published_at TIMESTAMPTZ;
  ALTER TABLE blog_drafts ADD COLUMN IF NOT EXISTS scheduled_at TIMESTAMPTZ;
EXCEPTION WHEN duplicate_column THEN NULL;
END $$;

-- ============================================================
-- SALES FORECAST (WS5)
-- ============================================================

CREATE TABLE IF NOT EXISTS sales_forecasts (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  technology      TEXT NOT NULL,               -- "400G QSFP-DD", "100G QSFP28", etc.
  speed_gbps      NUMERIC,
  form_factor     TEXT,

  -- Forecast periods
  forecast_3m_units   INTEGER,
  forecast_3m_revenue NUMERIC,
  forecast_9m_units   INTEGER,
  forecast_9m_revenue NUMERIC,
  forecast_12m_units  INTEGER,
  forecast_12m_revenue NUMERIC,
  forecast_18m_units  INTEGER,
  forecast_18m_revenue NUMERIC,

  -- Price trajectory
  current_asp         NUMERIC,
  asp_3m              NUMERIC,
  asp_12m             NUMERIC,
  price_floor         NUMERIC,
  months_to_floor     INTEGER,

  -- Confidence
  confidence_3m   NUMERIC,
  confidence_9m   NUMERIC,
  confidence_12m  NUMERIC,
  confidence_18m  NUMERIC,

  -- Buy signal
  buy_signal      TEXT CHECK (buy_signal IN ('BUY_NOW', 'WAIT', 'HOLD')),
  signal_reason   TEXT,

  -- Model info
  model_version   TEXT DEFAULT 'norton-bass-v1',
  data_points     INTEGER,                    -- how many price observations used

  computed_at     TIMESTAMPTZ DEFAULT NOW(),
  valid_until     TIMESTAMPTZ DEFAULT NOW() + INTERVAL '7 days'
);

CREATE INDEX IF NOT EXISTS idx_forecasts_tech ON sales_forecasts(technology);
CREATE INDEX IF NOT EXISTS idx_forecasts_computed ON sales_forecasts(computed_at DESC);

-- ============================================================
-- TRANSPORT PLANNER (WS3)
-- ============================================================

CREATE TABLE IF NOT EXISTS fiber_providers (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name            TEXT NOT NULL UNIQUE,
  slug            TEXT NOT NULL UNIQUE,
  website         TEXT,
  type            TEXT CHECK (type IN ('tier1', 'tier2', 'regional', 'municipal', 'hyperscaler')),
  headquarters    TEXT,
  coverage_countries TEXT[],
  products        TEXT[],                     -- 'dark_fiber', 'wavelength', 'ip_transit', 'ethernet'
  peering_ixs     TEXT[],                     -- IX names where they peer
  notes           TEXT,
  created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS fiber_routes (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  provider_id     UUID REFERENCES fiber_providers(id),
  city_a          TEXT NOT NULL,
  city_b          TEXT NOT NULL,
  country         TEXT DEFAULT 'DE',
  distance_km     NUMERIC,
  fiber_distance_km NUMERIC,                  -- actual fiber route (usually 1.3-1.5x straight line)
  product_type    TEXT,                        -- 'dark_fiber', 'wavelength_100g', 'wavelength_400g', etc.
  monthly_price_eur NUMERIC,
  setup_fee_eur   NUMERIC,
  min_contract_months INTEGER,
  latency_ms      NUMERIC,
  available       BOOLEAN DEFAULT TRUE,
  notes           TEXT,
  created_at      TIMESTAMPTZ DEFAULT NOW(),

  UNIQUE(provider_id, city_a, city_b, product_type)
);

CREATE TABLE IF NOT EXISTS cities (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name            TEXT NOT NULL,
  country         TEXT NOT NULL DEFAULT 'DE',
  lat             NUMERIC,
  lon             NUMERIC,
  has_ix          BOOLEAN DEFAULT FALSE,
  ix_names        TEXT[],
  has_datacenter  BOOLEAN DEFAULT FALSE,
  population      INTEGER,
  UNIQUE(name, country)
);

CREATE INDEX IF NOT EXISTS idx_fiber_routes_cities ON fiber_routes(city_a, city_b);
CREATE INDEX IF NOT EXISTS idx_cities_country ON cities(country);

-- ============================================================
-- GENERATED DATASHEETS (WS2)
-- ============================================================

CREATE TABLE IF NOT EXISTS generated_datasheets (
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  entity_type     TEXT NOT NULL CHECK (entity_type IN ('transceiver', 'switch', 'comparison', 'compatibility_matrix')),
  entity_id       UUID,
  entity_ids      UUID[],                     -- for comparison datasheets
  branding        TEXT DEFAULT 'flexoptix',
  format          TEXT DEFAULT 'pdf',

  r2_key          TEXT,
  r2_url          TEXT,
  file_size_bytes BIGINT,

  generated_at    TIMESTAMPTZ DEFAULT NOW(),
  expires_at      TIMESTAMPTZ DEFAULT NOW() + INTERVAL '30 days'
);

CREATE INDEX IF NOT EXISTS idx_datasheets_entity ON generated_datasheets(entity_type, entity_id);
