CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE TABLE IF NOT EXISTS model_catalog_providers (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  provider_key text NOT NULL UNIQUE,
  display_name text NOT NULL,
  provider_type text NOT NULL DEFAULT 'openai_compatible',
  capability_schema jsonb NOT NULL DEFAULT '{}'::jsonb,
  default_rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  status text NOT NULL DEFAULT 'active',
  metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_model_catalog_provider_status
  ON model_catalog_providers(status);

CREATE TABLE IF NOT EXISTS base_model_catalog (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  provider_id uuid REFERENCES model_catalog_providers(id) ON DELETE SET NULL,
  provider_key text NOT NULL,
  canonical_model_key text NOT NULL UNIQUE,
  provider_model_name text NOT NULL,
  model_type text NOT NULL,
  display_name text NOT NULL,
  capabilities jsonb NOT NULL DEFAULT '{}'::jsonb,
  base_billing_config jsonb NOT NULL DEFAULT '{}'::jsonb,
  default_rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  pricing_version integer NOT NULL DEFAULT 1,
  status text NOT NULL DEFAULT 'active',
  metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_base_model_catalog_provider
  ON base_model_catalog(provider_key, model_type, status);

CREATE INDEX IF NOT EXISTS idx_base_model_catalog_capabilities
  ON base_model_catalog USING gin(capabilities);

CREATE TABLE IF NOT EXISTS integration_platforms (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  provider text NOT NULL,
  platform_key text NOT NULL UNIQUE DEFAULT ('platform_' || replace(gen_random_uuid()::text, '-', '')),
  name text NOT NULL,
  base_url text,
  auth_type text NOT NULL DEFAULT 'bearer',
  credentials jsonb NOT NULL DEFAULT '{}'::jsonb,
  config jsonb NOT NULL DEFAULT '{}'::jsonb,
  default_pricing_mode text NOT NULL DEFAULT 'inherit_discount',
  default_discount_factor numeric NOT NULL DEFAULT 1,
  retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  priority integer NOT NULL DEFAULT 100,
  dynamic_priority integer,
  status text NOT NULL DEFAULT 'enabled',
  disabled_reason text,
  cooldown_until timestamptz,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  deleted_at timestamptz
);

CREATE INDEX IF NOT EXISTS idx_integration_platforms_provider_status
  ON integration_platforms(provider, status);

CREATE INDEX IF NOT EXISTS idx_integration_platforms_status_priority
  ON integration_platforms(status, priority, dynamic_priority);

CREATE INDEX IF NOT EXISTS idx_integration_platforms_cooldown
  ON integration_platforms(cooldown_until);

CREATE TABLE IF NOT EXISTS model_pricing_rules (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  scope_type text NOT NULL,
  scope_id uuid,
  resource_type text NOT NULL,
  unit text NOT NULL,
  base_price numeric NOT NULL,
  currency text NOT NULL DEFAULT 'resource',
  base_weight jsonb NOT NULL DEFAULT '{}'::jsonb,
  dynamic_weight jsonb NOT NULL DEFAULT '{}'::jsonb,
  effective_from timestamptz,
  effective_to timestamptz,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_model_pricing_scope
  ON model_pricing_rules(scope_type, scope_id, resource_type);

CREATE INDEX IF NOT EXISTS idx_model_pricing_effective
  ON model_pricing_rules(effective_from, effective_to);

CREATE TABLE IF NOT EXISTS platform_models (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  platform_id uuid NOT NULL REFERENCES integration_platforms(id) ON DELETE CASCADE,
  base_model_id uuid REFERENCES base_model_catalog(id) ON DELETE SET NULL,
  model_name text NOT NULL,
  model_alias text,
  model_type text NOT NULL,
  display_name text NOT NULL DEFAULT '',
  capability_override jsonb NOT NULL DEFAULT '{}'::jsonb,
  capabilities jsonb NOT NULL DEFAULT '{}'::jsonb,
  pricing_mode text NOT NULL DEFAULT 'inherit_discount',
  discount_factor numeric,
  billing_config_override jsonb NOT NULL DEFAULT '{}'::jsonb,
  billing_config jsonb NOT NULL DEFAULT '{}'::jsonb,
  permission_config jsonb NOT NULL DEFAULT '{}'::jsonb,
  retry_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  rate_limit_policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  enabled boolean NOT NULL DEFAULT true,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE(platform_id, model_name, model_type)
);

CREATE INDEX IF NOT EXISTS idx_platform_models_base
  ON platform_models(base_model_id);

CREATE INDEX IF NOT EXISTS idx_platform_models_lookup
  ON platform_models(model_type, model_name, enabled);

CREATE INDEX IF NOT EXISTS idx_platform_models_alias
  ON platform_models(model_alias);

CREATE INDEX IF NOT EXISTS idx_platform_models_capabilities
  ON platform_models USING gin(capabilities);

CREATE TABLE IF NOT EXISTS gateway_tasks (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  external_task_id text,
  kind text NOT NULL,
  run_mode text NOT NULL DEFAULT 'production',
  user_id text NOT NULL,
  tenant_id text,
  api_key_id text,
  model text NOT NULL,
  model_type text,
  request jsonb NOT NULL DEFAULT '{}'::jsonb,
  normalized_request jsonb NOT NULL DEFAULT '{}'::jsonb,
  status text NOT NULL DEFAULT 'queued',
  queue_key text NOT NULL DEFAULT 'default',
  priority integer NOT NULL DEFAULT 100,
  idempotency_key text,
  remote_task_id text,
  remote_task_payload jsonb,
  simulation_profile jsonb,
  simulation_seed text,
  locked_by text,
  locked_at timestamptz,
  heartbeat_at timestamptz,
  next_run_at timestamptz NOT NULL DEFAULT now(),
  attempt_count integer NOT NULL DEFAULT 0,
  max_attempts integer NOT NULL DEFAULT 1,
  result jsonb,
  billings jsonb,
  error text,
  error_code text,
  error_message text,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  finished_at timestamptz
);

CREATE INDEX IF NOT EXISTS idx_gateway_tasks_queue
  ON gateway_tasks(status, next_run_at, priority, created_at);

CREATE INDEX IF NOT EXISTS idx_gateway_tasks_lease
  ON gateway_tasks(status, heartbeat_at);

CREATE INDEX IF NOT EXISTS idx_gateway_tasks_user_created
  ON gateway_tasks(user_id, created_at DESC);

CREATE INDEX IF NOT EXISTS idx_gateway_tasks_external
  ON gateway_tasks(external_task_id);

CREATE UNIQUE INDEX IF NOT EXISTS uniq_gateway_tasks_idempotency
  ON gateway_tasks(user_id, idempotency_key)
  WHERE idempotency_key IS NOT NULL;

CREATE TABLE IF NOT EXISTS gateway_task_attempts (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE,
  attempt_no integer NOT NULL,
  platform_id uuid REFERENCES integration_platforms(id) ON DELETE SET NULL,
  platform_model_id uuid REFERENCES platform_models(id) ON DELETE SET NULL,
  client_id text,
  queue_key text NOT NULL,
  status text NOT NULL,
  retryable boolean NOT NULL DEFAULT false,
  simulated boolean NOT NULL DEFAULT false,
  remote_task_id text,
  request_snapshot jsonb NOT NULL DEFAULT '{}'::jsonb,
  response_snapshot jsonb,
  error_code text,
  error_message text,
  started_at timestamptz NOT NULL DEFAULT now(),
  finished_at timestamptz,
  UNIQUE(task_id, attempt_no)
);

CREATE INDEX IF NOT EXISTS idx_gateway_attempts_task
  ON gateway_task_attempts(task_id);

CREATE INDEX IF NOT EXISTS idx_gateway_attempts_client
  ON gateway_task_attempts(client_id, started_at DESC);

CREATE TABLE IF NOT EXISTS gateway_task_events (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE,
  seq bigint NOT NULL,
  event_type text NOT NULL,
  status text,
  phase text,
  progress numeric,
  message text,
  payload jsonb NOT NULL DEFAULT '{}'::jsonb,
  simulated boolean NOT NULL DEFAULT false,
  created_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE(task_id, seq)
);

CREATE INDEX IF NOT EXISTS idx_gateway_events_task_created
  ON gateway_task_events(task_id, created_at);

CREATE TABLE IF NOT EXISTS runtime_client_states (
  client_id text PRIMARY KEY,
  platform_id uuid REFERENCES integration_platforms(id) ON DELETE SET NULL,
  provider text NOT NULL,
  method_name text NOT NULL,
  queue_key text NOT NULL,
  running_count integer NOT NULL DEFAULT 0,
  waiting_count integer NOT NULL DEFAULT 0,
  limiter_ratio numeric NOT NULL DEFAULT 0,
  cooldown_until timestamptz,
  last_assigned_at timestamptz,
  last_error text,
  updated_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_runtime_client_queue
  ON runtime_client_states(queue_key, cooldown_until);

CREATE INDEX IF NOT EXISTS idx_runtime_client_platform
  ON runtime_client_states(platform_id);

CREATE TABLE IF NOT EXISTS gateway_upload_assets (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  task_id uuid REFERENCES gateway_tasks(id) ON DELETE SET NULL,
  source text NOT NULL,
  server_main_file_id text,
  url text NOT NULL,
  object_key text,
  content_type text,
  size bigint,
  checksum text,
  metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_gateway_upload_task
  ON gateway_upload_assets(task_id);

CREATE INDEX IF NOT EXISTS idx_gateway_upload_file
  ON gateway_upload_assets(server_main_file_id);

CREATE TABLE IF NOT EXISTS gateway_retry_policies (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  scope_type text NOT NULL,
  scope_key text NOT NULL,
  enabled boolean NOT NULL DEFAULT true,
  policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE(scope_type, scope_key)
);

CREATE TABLE IF NOT EXISTS gateway_rate_limit_policies (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  scope_type text NOT NULL,
  scope_key text NOT NULL,
  policy jsonb NOT NULL DEFAULT '{}'::jsonb,
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE(scope_type, scope_key)
);

CREATE TABLE IF NOT EXISTS gateway_rate_limit_counters (
  scope_type text NOT NULL,
  scope_key text NOT NULL,
  metric text NOT NULL,
  window_start timestamptz NOT NULL,
  limit_value numeric NOT NULL,
  used_value numeric NOT NULL DEFAULT 0,
  reserved_value numeric NOT NULL DEFAULT 0,
  reset_at timestamptz NOT NULL,
  updated_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY(scope_type, scope_key, metric, window_start)
);

CREATE TABLE IF NOT EXISTS gateway_concurrency_leases (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE,
  attempt_id uuid REFERENCES gateway_task_attempts(id) ON DELETE SET NULL,
  scope_type text NOT NULL,
  scope_key text NOT NULL,
  lease_value numeric NOT NULL DEFAULT 1,
  acquired_at timestamptz NOT NULL DEFAULT now(),
  expires_at timestamptz NOT NULL,
  released_at timestamptz
);

CREATE INDEX IF NOT EXISTS idx_concurrency_leases_active
  ON gateway_concurrency_leases(scope_type, scope_key, released_at, expires_at);

CREATE INDEX IF NOT EXISTS idx_concurrency_leases_task
  ON gateway_concurrency_leases(task_id);

CREATE TABLE IF NOT EXISTS settlement_outbox (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  task_id uuid NOT NULL REFERENCES gateway_tasks(id) ON DELETE CASCADE,
  event_type text NOT NULL DEFAULT 'task.settlement.requested',
  payload jsonb NOT NULL,
  status text NOT NULL DEFAULT 'pending',
  attempts integer NOT NULL DEFAULT 0,
  next_attempt_at timestamptz NOT NULL DEFAULT now(),
  created_at timestamptz NOT NULL DEFAULT now(),
  updated_at timestamptz NOT NULL DEFAULT now(),
  UNIQUE(task_id, event_type)
);
