CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE TABLE IF NOT EXISTS admin_users (
  id BIGSERIAL PRIMARY KEY,
  username TEXT NOT NULL UNIQUE,
  password_hash TEXT NOT NULL,
  role TEXT NOT NULL,
  status TEXT NOT NULL,
  session_version INTEGER NOT NULL DEFAULT 1,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE TABLE IF NOT EXISTS admin_audit_logs (
  id BIGSERIAL PRIMARY KEY,
  actor_user_id BIGINT,
  actor_username TEXT NOT NULL DEFAULT '',
  actor_role TEXT NOT NULL DEFAULT '',
  action TEXT NOT NULL,
  target_type TEXT NOT NULL,
  target_id TEXT NOT NULL,
  payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_created_at ON admin_audit_logs(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_target ON admin_audit_logs(target_type, target_id);

CREATE TABLE IF NOT EXISTS fulfillment_profiles (
  id BIGSERIAL PRIMARY KEY,
  profile_key TEXT NOT NULL UNIQUE,
  name TEXT NOT NULL,
  executor_key TEXT NOT NULL,
  requires_claim BOOLEAN NOT NULL DEFAULT FALSE,
  auto_dispatch BOOLEAN NOT NULL DEFAULT FALSE,
  inventory_strategy TEXT NOT NULL DEFAULT 'static_pool',
  config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE TABLE IF NOT EXISTS fulfillment_profile_requirements (
  id BIGSERIAL PRIMARY KEY,
  profile_id BIGINT NOT NULL REFERENCES fulfillment_profiles(id) ON DELETE CASCADE,
  role_key TEXT NOT NULL,
  credential_type TEXT NOT NULL,
  quantity_per_unit INTEGER NOT NULL DEFAULT 1,
  is_required BOOLEAN NOT NULL DEFAULT TRUE,
  config_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL,
  UNIQUE(profile_id, role_key)
);

CREATE TABLE IF NOT EXISTS orders (
  id BIGSERIAL PRIMARY KEY,
  provider TEXT NOT NULL,
  platform TEXT NOT NULL,
  shop_id TEXT NOT NULL DEFAULT '',
  shop_name TEXT NOT NULL DEFAULT '',
  platform_order_id TEXT NOT NULL,
  order_status TEXT NOT NULL DEFAULT 'created',
  pay_status TEXT NOT NULL DEFAULT 'unpaid',
  buyer_id TEXT NOT NULL DEFAULT '',
  buyer_name TEXT NOT NULL DEFAULT '',
  receiver_contact TEXT NOT NULL DEFAULT '',
  total_amount INTEGER NOT NULL DEFAULT 0,
  currency TEXT NOT NULL DEFAULT 'CNY',
  raw_payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  paid_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL,
  UNIQUE(provider, platform, shop_id, platform_order_id)
);

CREATE INDEX IF NOT EXISTS idx_orders_platform_order_lookup
  ON orders(provider, platform, platform_order_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_orders_created_at_desc
  ON orders(created_at DESC);

CREATE TABLE IF NOT EXISTS order_items (
  id BIGSERIAL PRIMARY KEY,
  order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
  sku_code TEXT NOT NULL,
  sku_name TEXT NOT NULL DEFAULT '',
  quantity INTEGER NOT NULL DEFAULT 1,
  spec_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  item_snapshot_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_order_items_order_id ON order_items(order_id);
CREATE INDEX IF NOT EXISTS idx_order_items_sku_code ON order_items(sku_code);

CREATE TABLE IF NOT EXISTS fulfillment_tasks (
  id BIGSERIAL PRIMARY KEY,
  order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
  order_item_id BIGINT NOT NULL REFERENCES order_items(id) ON DELETE CASCADE,
  unit_index INTEGER NOT NULL DEFAULT 1,
  task_no TEXT NOT NULL UNIQUE,
  provider TEXT NOT NULL,
  platform TEXT NOT NULL,
  shop_id TEXT NOT NULL DEFAULT '',
  shop_name TEXT NOT NULL DEFAULT '',
  platform_order_id TEXT NOT NULL,
  profile_id BIGINT NOT NULL REFERENCES fulfillment_profiles(id) ON DELETE RESTRICT,
  executor_key TEXT NOT NULL,
  task_status TEXT NOT NULL DEFAULT 'pending_payment',
  delivery_status TEXT NOT NULL DEFAULT 'pending',
  result_code TEXT NOT NULL DEFAULT '',
  result_message TEXT NOT NULL DEFAULT '',
  claim_token TEXT NOT NULL DEFAULT '',
  claim_expires_at TIMESTAMPTZ,
  automation_mode TEXT NOT NULL DEFAULT 'manual',
  requires_claim BOOLEAN NOT NULL DEFAULT FALSE,
  user_action_status TEXT NOT NULL DEFAULT 'not_required',
  attempt_count INTEGER NOT NULL DEFAULT 0,
  last_error TEXT NOT NULL DEFAULT '',
  context_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  claimed_at TIMESTAMPTZ,
  role_confirmed_at TIMESTAMPTZ,
  redeemed_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL,
  UNIQUE(order_item_id, unit_index)
);

CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_status ON fulfillment_tasks(task_status, delivery_status);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_order ON fulfillment_tasks(order_id, order_item_id);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_claim_token ON fulfillment_tasks(claim_token);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_platform_order_lookup
  ON fulfillment_tasks(provider, platform, platform_order_id, id DESC);
CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_created_at_desc
  ON fulfillment_tasks(created_at DESC);

CREATE TABLE IF NOT EXISTS claim_tokens (
  id BIGSERIAL PRIMARY KEY,
  task_id BIGINT NOT NULL UNIQUE REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
  token TEXT NOT NULL UNIQUE,
  status TEXT NOT NULL DEFAULT 'active',
  expired_at TIMESTAMPTZ NOT NULL,
  used_at TIMESTAMPTZ,
  max_use_count INTEGER NOT NULL DEFAULT 1,
  used_count INTEGER NOT NULL DEFAULT 0,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_claim_tokens_status ON claim_tokens(status, expired_at);

CREATE TABLE IF NOT EXISTS task_events (
  id BIGSERIAL PRIMARY KEY,
  task_id BIGINT NOT NULL REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
  event_type TEXT NOT NULL,
  payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_task_events_task_created_at ON task_events(task_id, created_at DESC);

CREATE TABLE IF NOT EXISTS task_runtime_contexts (
  id BIGSERIAL PRIMARY KEY,
  task_id BIGINT NOT NULL UNIQUE REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
  runtime_session_id TEXT NOT NULL DEFAULT '',
  login_type TEXT NOT NULL DEFAULT '',
  nickname TEXT NOT NULL DEFAULT '',
  role_id TEXT NOT NULL DEFAULT '',
  role_name TEXT NOT NULL DEFAULT '',
  area TEXT NOT NULL DEFAULT '',
  partition_name TEXT NOT NULL DEFAULT '',
  screenshot_path TEXT NOT NULL DEFAULT '',
  artifacts_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  state_json JSONB NOT NULL DEFAULT '{}'::jsonb,
  created_at TIMESTAMPTZ NOT NULL,
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE TABLE IF NOT EXISTS kuaishou_cloud_task_states (
  task_id BIGINT PRIMARY KEY REFERENCES fulfillment_tasks(id) ON DELETE CASCADE,
  ticket_status TEXT NOT NULL DEFAULT 'pending',
  ticket_code_masked TEXT NOT NULL DEFAULT '',
  bind_url TEXT NOT NULL DEFAULT '',
  vn_phone TEXT NOT NULL DEFAULT '',
  role_name TEXT NOT NULL DEFAULT '',
  role_id TEXT NOT NULL DEFAULT '',
  dispatch_status TEXT NOT NULL DEFAULT 'pending',
  consume_status TEXT NOT NULL DEFAULT 'pending',
  source_key TEXT NOT NULL DEFAULT '',
  updated_at TIMESTAMPTZ NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_role_id
  ON kuaishou_cloud_task_states(role_id);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_source_key
  ON kuaishou_cloud_task_states(source_key);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_dispatch_status
  ON kuaishou_cloud_task_states(dispatch_status);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_consume_status
  ON kuaishou_cloud_task_states(consume_status);
CREATE INDEX IF NOT EXISTS idx_kuaishou_cloud_task_states_updated_at_desc
  ON kuaishou_cloud_task_states(updated_at DESC);
