-- Migration 084: Dual Transport Preflight System
-- Workers run both curl and http (Puppeteer) preflights on startup
-- Tasks can require a specific transport method

-- ===================================================================
-- PART 1: Add preflight columns to worker_registry
-- ===================================================================

-- Preflight status for curl/axios transport (proxy-based)
ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_curl_status VARCHAR(20) DEFAULT 'pending';

-- Preflight status for http/Puppeteer transport (browser-based)
ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_http_status VARCHAR(20) DEFAULT 'pending';

-- Timestamps for when each preflight completed
ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_curl_at TIMESTAMPTZ;

ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_http_at TIMESTAMPTZ;

-- Error messages for failed preflights
ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_curl_error TEXT;

ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_http_error TEXT;

-- Response time for successful preflights (ms)
ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_curl_ms INTEGER;

ALTER TABLE worker_registry
ADD COLUMN IF NOT EXISTS preflight_http_ms INTEGER;

-- Constraints for preflight status values
ALTER TABLE worker_registry
DROP CONSTRAINT IF EXISTS valid_preflight_curl_status;

ALTER TABLE worker_registry
ADD CONSTRAINT valid_preflight_curl_status
CHECK (preflight_curl_status IN ('pending', 'passed', 'failed', 'skipped'));

ALTER TABLE worker_registry
DROP CONSTRAINT IF EXISTS valid_preflight_http_status;

ALTER TABLE worker_registry
ADD CONSTRAINT valid_preflight_http_status
CHECK (preflight_http_status IN ('pending', 'passed', 'failed', 'skipped'));

-- ===================================================================
-- PART 2: Add method column to worker_tasks
-- ===================================================================

-- Transport method requirement for the task
-- NULL = no preference (any worker can claim)
-- 'curl' = requires curl/axios transport (proxy-based, fast)
-- 'http' = requires http/Puppeteer transport (browser-based, anti-detect)
ALTER TABLE worker_tasks
ADD COLUMN IF NOT EXISTS method VARCHAR(10);

-- Constraint for valid method values
ALTER TABLE worker_tasks
DROP CONSTRAINT IF EXISTS valid_task_method;

ALTER TABLE worker_tasks
ADD CONSTRAINT valid_task_method
CHECK (method IS NULL OR method IN ('curl', 'http'));

-- Index for method-based task claiming
CREATE INDEX IF NOT EXISTS idx_worker_tasks_method
  ON worker_tasks(method)
  WHERE status = 'pending';

-- Set default method for all existing pending tasks to 'http'
-- ALL current tasks require Puppeteer/browser-based transport
UPDATE worker_tasks
SET method = 'http'
WHERE method IS NULL;

-- ===================================================================
-- PART 3: Update claim_task function for method compatibility
-- ===================================================================

CREATE OR REPLACE FUNCTION claim_task(
  p_role VARCHAR(50),
  p_worker_id VARCHAR(100),
  p_curl_passed BOOLEAN DEFAULT TRUE,
  p_http_passed BOOLEAN DEFAULT FALSE
) RETURNS worker_tasks AS $$
DECLARE
  claimed_task worker_tasks;
BEGIN
  UPDATE worker_tasks
  SET
    status = 'claimed',
    worker_id = p_worker_id,
    claimed_at = NOW(),
    updated_at = NOW()
  WHERE id = (
    SELECT id FROM worker_tasks
    WHERE role = p_role
      AND status = 'pending'
      AND (scheduled_for IS NULL OR scheduled_for <= NOW())
      -- Method compatibility: worker must have passed the required preflight
      AND (
        method IS NULL  -- No preference, any worker can claim
        OR (method = 'curl' AND p_curl_passed = TRUE)
        OR (method = 'http' AND p_http_passed = TRUE)
      )
      -- Exclude stores that already have an active task
      AND (dispensary_id IS NULL OR dispensary_id NOT IN (
        SELECT dispensary_id FROM worker_tasks
        WHERE status IN ('claimed', 'running')
        AND dispensary_id IS NOT NULL
      ))
    ORDER BY priority DESC, created_at ASC
    LIMIT 1
    FOR UPDATE SKIP LOCKED
  )
  RETURNING * INTO claimed_task;

  RETURN claimed_task;
END;
$$ LANGUAGE plpgsql;

-- ===================================================================
-- PART 4: Update v_active_workers view
-- ===================================================================

DROP VIEW IF EXISTS v_active_workers;

CREATE VIEW v_active_workers AS
SELECT
  wr.id,
  wr.worker_id,
  wr.friendly_name,
  wr.role,
  wr.status,
  wr.pod_name,
  wr.hostname,
  wr.started_at,
  wr.last_heartbeat_at,
  wr.last_task_at,
  wr.tasks_completed,
  wr.tasks_failed,
  wr.current_task_id,
  -- Preflight status
  wr.preflight_curl_status,
  wr.preflight_http_status,
  wr.preflight_curl_at,
  wr.preflight_http_at,
  wr.preflight_curl_error,
  wr.preflight_http_error,
  wr.preflight_curl_ms,
  wr.preflight_http_ms,
  -- Computed fields
  EXTRACT(EPOCH FROM (NOW() - wr.last_heartbeat_at)) as seconds_since_heartbeat,
  CASE
    WHEN wr.status = 'offline' THEN 'offline'
    WHEN wr.last_heartbeat_at < NOW() - INTERVAL '2 minutes' THEN 'stale'
    WHEN wr.current_task_id IS NOT NULL THEN 'busy'
    ELSE 'ready'
  END as health_status,
  -- Capability flags (can this worker handle curl/http tasks?)
  (wr.preflight_curl_status = 'passed') as can_curl,
  (wr.preflight_http_status = 'passed') as can_http
FROM worker_registry wr
WHERE wr.status != 'terminated'
ORDER BY wr.status = 'active' DESC, wr.last_heartbeat_at DESC;

-- ===================================================================
-- PART 5: View for task queue with method info
-- ===================================================================

DROP VIEW IF EXISTS v_task_history;

CREATE VIEW v_task_history AS
SELECT
  t.id,
  t.role,
  t.dispensary_id,
  d.name as dispensary_name,
  t.platform,
  t.status,
  t.priority,
  t.method,
  t.worker_id,
  t.scheduled_for,
  t.claimed_at,
  t.started_at,
  t.completed_at,
  t.error_message,
  t.retry_count,
  t.created_at,
  EXTRACT(EPOCH FROM (t.completed_at - t.started_at)) as duration_sec
FROM worker_tasks t
LEFT JOIN dispensaries d ON d.id = t.dispensary_id
ORDER BY t.created_at DESC;

-- ===================================================================
-- PART 6: Helper function to update worker preflight status
-- ===================================================================

CREATE OR REPLACE FUNCTION update_worker_preflight(
  p_worker_id VARCHAR(100),
  p_transport VARCHAR(10),  -- 'curl' or 'http'
  p_status VARCHAR(20),     -- 'passed', 'failed', 'skipped'
  p_response_ms INTEGER DEFAULT NULL,
  p_error TEXT DEFAULT NULL
) RETURNS VOID AS $$
BEGIN
  IF p_transport = 'curl' THEN
    UPDATE worker_registry
    SET
      preflight_curl_status = p_status,
      preflight_curl_at = NOW(),
      preflight_curl_ms = p_response_ms,
      preflight_curl_error = p_error,
      updated_at = NOW()
    WHERE worker_id = p_worker_id;
  ELSIF p_transport = 'http' THEN
    UPDATE worker_registry
    SET
      preflight_http_status = p_status,
      preflight_http_at = NOW(),
      preflight_http_ms = p_response_ms,
      preflight_http_error = p_error,
      updated_at = NOW()
    WHERE worker_id = p_worker_id;
  END IF;
END;
$$ LANGUAGE plpgsql;

-- ===================================================================
-- Comments
-- ===================================================================

COMMENT ON COLUMN worker_registry.preflight_curl_status IS 'Status of curl/axios preflight: pending, passed, failed, skipped';
COMMENT ON COLUMN worker_registry.preflight_http_status IS 'Status of http/Puppeteer preflight: pending, passed, failed, skipped';
COMMENT ON COLUMN worker_registry.preflight_curl_at IS 'When curl preflight completed';
COMMENT ON COLUMN worker_registry.preflight_http_at IS 'When http preflight completed';
COMMENT ON COLUMN worker_registry.preflight_curl_error IS 'Error message if curl preflight failed';
COMMENT ON COLUMN worker_registry.preflight_http_error IS 'Error message if http preflight failed';
COMMENT ON COLUMN worker_registry.preflight_curl_ms IS 'Response time of successful curl preflight (ms)';
COMMENT ON COLUMN worker_registry.preflight_http_ms IS 'Response time of successful http preflight (ms)';

COMMENT ON COLUMN worker_tasks.method IS 'Transport method required: NULL=any, curl=proxy-based, http=browser-based';

COMMENT ON FUNCTION claim_task IS 'Atomically claim a task, respecting method requirements and per-store locking';
COMMENT ON FUNCTION update_worker_preflight IS 'Update a workers preflight status for a given transport';
