/**
 * @agent-bounty/contracts — Zod Validation Schemas
 *
 * 唯一的驗證真實來源。
 * MCP server、後端 API、前端表單都必須 import 這裡的 schema，
 * 禁止在各自的程式庫中重新定義任何 VibeWork 資料結構。
 */

import { z } from "zod";
import {
  TaskStatus,
  TaskDifficulty,
  ValidationMode,
  JudgeOverallResult,
  JudgeTestStatus,
  JudgeErrorClassification,
  SettlementPhase,
  SettlementCaptureMode,
  SupportedCurrency,
  LeadStatus,
  AttributionModel,
  TaskErrorClassification,
  MAX_TASK_RETRY_COUNT,
} from "../enums/index.js";

// ─────────────────────────────────────────────
// 通用基礎型別
// ─────────────────────────────────────────────

const UUIDSchema = z.string().uuid("無效的 UUID 格式");
const CUIDSchema = z.string().cuid("無效的 CUID 格式");
const PositiveIntSchema = z.number().int().positive();
const NonNegativeIntSchema = z.number().int().nonnegative();

/** 金額（以最小單位計，例如美分 / 台幣分） */
const MoneyAmountSchema = z
  .number()
  .int()
  .nonnegative("金額不得為負數")
  .max(1_000_000_00, "單筆金額超過上限（$1,000,000）");

/** scope_clarity_score：AI 評估任務清晰度，Phase 1 要求 ≥ 0.90 */
const ScopeScoreSchema = z
  .number()
  .min(0)
  .max(1)
  .refine((v) => v >= 0.9, {
    message: "scope_clarity_score 必須 ≥ 0.90 才能進入主任務池",
  });

// ─────────────────────────────────────────────
// Task 驗收條件 Schema
// ─────────────────────────────────────────────

export const AcceptanceCriteriaSchema = z.object({
  validation_mode: z.enum([
    ValidationMode.VITEST_UNIT,
    ValidationMode.PLAYWRIGHT_E2E,
    ValidationMode.AST_PARSING,
    ValidationMode.VISUAL_REGRESSION,
  ]),
  /** 由平台提供的最小測試檔內容（string）；Agent 不得修改此欄位 */
  test_file_content: z.string().min(20, "測試檔內容不得為空"),
  /** 關鍵斷言規則（可選，補充說明） */
  rules: z
    .array(
      z.object({
        assertion: z.string(),
        expected: z.unknown(),
        description: z.string().optional(),
      })
    )
    .optional(),
});

// ─────────────────────────────────────────────
// Task Bounty 核心 Schema（Open Bounty Board）
// ─────────────────────────────────────────────

export const TaskBountySchema = z.object({
  task_id: UUIDSchema,
  title: z.string().min(5).max(120),
  description: z.string().min(20).max(2000),
  status: z.enum([
    TaskStatus.DRAFT,
    TaskStatus.OPEN,
    TaskStatus.EXECUTING,
    TaskStatus.VERIFYING,
    TaskStatus.COMPLETED,
    TaskStatus.FAILED,
    TaskStatus.FAILED_RETRYABLE,
    TaskStatus.CANCELLED,
    TaskStatus.DISPUTED,
    TaskStatus.REFUND_PENDING,
    TaskStatus.PAYOUT_READY,
    TaskStatus.PAYOUT_SETTLED,
    TaskStatus.ARCHIVED,
  ]),
  difficulty: z.enum([
    TaskDifficulty.HELLO_WORLD,
    TaskDifficulty.COMPONENT,
    TaskDifficulty.VIEW,
    TaskDifficulty.EPIC,
  ]),
  /** 最小可行要求 ≥ 0.90 才能進入公開任務池 */
  scope_clarity_score: ScopeScoreSchema,
  error_classification: z.enum([
    TaskErrorClassification.RETRYABLE,
    TaskErrorClassification.NON_RETRYABLE,
  ]),
  reward: z.object({
    /** 金額（整數，以最小貨幣單位計：USD cents / TWD 元） */
    amount: MoneyAmountSchema,
    currency: z.enum([
      SupportedCurrency.USD,
      SupportedCurrency.TWD,
      SupportedCurrency.USDC,
    ]),
    /** 顯示用格式化金額（例如 "NT$30" / "$1.00"），由後端產生 */
    display_amount: z.string().optional(),
  }),
  acceptance_criteria: AcceptanceCriteriaSchema,
  /** 要求使用的技術棧 */
  required_stack: z.array(z.string()).min(1).default(["React", "Tailwind CSS"]),
  /** 已重試次數 */
  retry_count: NonNegativeIntSchema.max(MAX_TASK_RETRY_COUNT).default(0),
  /** Auth-Hold 的 Stripe payment_intent_id */
  stripe_payment_intent_id: z.string().optional(),
  /** 任務到期時間（對應 Redis TTL） */
  expires_at: z.string().datetime().optional(),
  created_at: z.string().datetime(),
  updated_at: z.string().datetime(),
});

// ─────────────────────────────────────────────
// claim_task Request/Response
// ─────────────────────────────────────────────

export const ClaimTaskRequestSchema = z.object({
  task_id: UUIDSchema,
  agent_id: z.string().min(1, "必須提供 agent_id 進行白名單驗證"),
  /** Agent 收款錢包（Stripe Connect account 或 EVM 地址） */
  developer_wallet: z
    .string()
    .regex(
      /^(0x[a-fA-F0-9]{40}|acct_[a-zA-Z0-9]+)$/,
      "developer_wallet 必須是有效的 EVM 地址或 Stripe Connect ID"
    ),
});

export const ClaimTaskResponseSchema = z.object({
  task_id: UUIDSchema,
  status: z.literal(TaskStatus.EXECUTING),
  /** Stripe Auth-Hold 的金額（供 Agent 確認） */
  held_amount: MoneyAmountSchema,
  held_currency: z.enum([SupportedCurrency.USD, SupportedCurrency.TWD]),
  /** Redis TTL 過期時間 */
  expires_at: z.string().datetime(),
  /** 接案 Agent 的冪等憑證 */
  claim_token: z.string().uuid(),
});

// ─────────────────────────────────────────────
// submit_solution Request/Response
// ─────────────────────────────────────────────

export const SubmitSolutionRequestSchema = z.object({
  task_id: UUIDSchema,
  /** 接案時取得的冪等憑證，防止重複提交 */
  claim_token: z.string().uuid(),
  deliverables: z.record(z.string(), z.string()),
});

export const SubmitSolutionResponseSchema = z.object({
  task_id: UUIDSchema,
  submission_id: UUIDSchema,
  status: z.literal(TaskStatus.VERIFYING),
  /** Judge 預計完成時間（ISO 8601） */
  estimated_judge_complete_at: z.string().datetime().optional(),
});

// ─────────────────────────────────────────────
// Judge Result Schema（E2B 沙盒回傳）
// ─────────────────────────────────────────────

export const JudgeTestResultSchema = z.object({
  name: z.string(),
  status: z.enum([
    JudgeTestStatus.PASSED,
    JudgeTestStatus.FAILED,
    JudgeTestStatus.SKIPPED,
  ]),
  duration_ms: NonNegativeIntSchema,
  logs: z.string().optional(),
  assertion_diff: z.string().optional(),
});

export const JudgeResultSchema = z.object({
  attempt_id: UUIDSchema,
  task_id: UUIDSchema,
  submission_id: UUIDSchema,
  overall_result: z.enum([
    JudgeOverallResult.PASS,
    JudgeOverallResult.FAIL,
    JudgeOverallResult.TIMEOUT,
  ]),
  tests: z.array(JudgeTestResultSchema),
  artifacts: z
    .object({
      screenshot_url: z.string().url().optional(),
      logs_url: z.string().url().optional(),
      coverage_summary: z.string().optional(),
      diff_url: z.string().url().optional(),
    })
    .optional(),
  /** 失敗類型（overall_result=fail/timeout 時必填） */
  error_classification: z
    .enum([
      JudgeErrorClassification.TEST_FAIL,
      JudgeErrorClassification.LINT_FAIL,
      JudgeErrorClassification.TIMEOUT,
      JudgeErrorClassification.RESOURCE_EXHAUSTED,
      JudgeErrorClassification.ENVIRONMENT_ERROR,
      JudgeErrorClassification.NETWORK_DENIED,
      JudgeErrorClassification.SANDBOX_CRASH,
      JudgeErrorClassification.TEST_SETUP_FAIL,
      JudgeErrorClassification.ENV_MISCONFIG,
    ])
    .optional(),
  /** 供 Builder/Scout 質量分數模型使用的錯誤指紋 */
  error_signature: z.string().optional(),
  /** 若為 true，後端可以安排重試（不計入 Agent 失敗分數） */
  retryable: z.boolean(),
  resource_usage: z.object({
    cpu_ms: NonNegativeIntSchema,
    mem_peak_mb: NonNegativeIntSchema,
    io_bytes: NonNegativeIntSchema,
  }),
  judge_completed_at: z.string().datetime(),
});

// ─────────────────────────────────────────────
// Settlement Ledger Schema（對帳台帳）
// ─────────────────────────────────────────────

export const SettlementLedgerEntrySchema = z.object({
  id: CUIDSchema,
  task_id: UUIDSchema,
  agent_id: z.string(),
  human_client_id: z.string(),
  /** Stripe 冪等 key：格式 "{task_id}_{phase}_{attempt}" */
  idempotency_key: z.string().min(10).max(255),
  phase: z.enum([
    SettlementPhase.AUTH_HOLD,
    SettlementPhase.CAPTURE,
    SettlementPhase.RELEASE,
    SettlementPhase.REFUND,
    SettlementPhase.PAYOUT,
    SettlementPhase.DISPUTE,
    SettlementPhase.CORRECTION,
  ]),
  capture_mode: z.enum([
    SettlementCaptureMode.STRIPE_AUTH_CAPTURE,
    SettlementCaptureMode.BASE_SMART_CONTRACT,
  ]),
  /** Stripe object ID（payment_intent_id / charge_id / refund_id） */
  stripe_object_id: z.string().optional(),
  amount: MoneyAmountSchema,
  currency: z.enum([SupportedCurrency.USD, SupportedCurrency.TWD]),
  request_payload_hash: z.string(),
  response_status: z.string(),
  http_status: z.number().int().min(100).max(599),
  attempt: PositiveIntSchema,
  source: z.enum(["api", "webhook", "manual_replay"]),
  /** 分潤快照（capture 時寫入，不得事後修改） */
  split: z
    .object({
      platform_amount: MoneyAmountSchema,
      builder_amount: MoneyAmountSchema,
      scout_amount: MoneyAmountSchema.optional(),
      platform_rate: z.number().min(0).max(1),
      builder_rate: z.number().min(0).max(1),
      scout_rate: z.number().min(0).max(1).optional(),
    })
    .optional(),
  created_at: z.string().datetime(),
  updated_at: z.string().datetime(),
});

// ─────────────────────────────────────────────
// Scout Draft / Lead Schemas
// ─────────────────────────────────────────────

export const ScoutDraftRequestSchema = z.object({
  scout_id: z.string().min(1, "必須提供 scout_id 進行歸因"),
  title: z.string().min(5).max(120),
  description: z.string().min(20).max(2000),
  reward_amount: MoneyAmountSchema,
  reward_currency: z.enum([SupportedCurrency.USD, SupportedCurrency.TWD]),
  required_stack: z.array(z.string()).default(["React", "Tailwind CSS"]),
  test_file_content: z.string().min(20, "必須提供測試檔以便自動驗收"),
});

export const ScoutDraftResponseSchema = z.object({
  task_id: UUIDSchema,
  checkout_url: z.string().url(),
  status: z.union([
    z.literal(TaskStatus.DRAFT),
    z.literal(TaskStatus.OPEN),
  ]),
});

export const LeadSchema = z.object({
  lead_id: UUIDSchema,
  scout_agent_id: z.string().optional(),
  /** Scout 的 affiliate token，用於歸因 */
  affiliate_token: z.string().uuid().optional(),
  attribution_model: z.enum([
    AttributionModel.LAST_CLICK,
    AttributionModel.FIRST_CLICK,
    AttributionModel.LINEAR,
  ]),
  status: z.enum([
    LeadStatus.DRAFT,
    LeadStatus.CONFIRMED,
    LeadStatus.PAYMENT_AUTHORIZED,
    LeadStatus.TASK_CREATED,
    LeadStatus.EXPIRED,
    LeadStatus.CANCELLED,
  ]),
  /** 需求者原始需求（純文字，不超過 500 字） */
  raw_requirement: z.string().min(10).max(500),
  /** AI 生成的 PRD 草稿（JSON） */
  prd_draft: z.record(z.string(), z.unknown()).optional(),
  /** 付款連結（Stripe Checkout URL） */
  payment_link: z.string().url().optional(),
  /** 付款連結 TTL 過期時間 */
  payment_link_expires_at: z.string().datetime().optional(),
  /** 成功後建立的正式 task_id */
  task_id: UUIDSchema.optional(),
  created_at: z.string().datetime(),
  updated_at: z.string().datetime(),
});

// ─────────────────────────────────────────────
// list_open_tasks Response Schema
// ─────────────────────────────────────────────

export const ListOpenTasksRequestSchema = z.object({
  skills: z
    .array(z.string().min(1).max(50))
    .min(1, "至少需要指定一個技能"),
  limit: z.number().int().min(1).max(20).default(5),
  difficulty: z
    .enum([
      TaskDifficulty.HELLO_WORLD,
      TaskDifficulty.COMPONENT,
      TaskDifficulty.VIEW,
      TaskDifficulty.EPIC,
    ])
    .optional(),
});

/** 精簡版 Task（list 用，避免暴露內部欄位） */
export const TaskSummarySchema = TaskBountySchema.pick({
  task_id: true,
  title: true,
  status: true,
  difficulty: true,
  reward: true,
  required_stack: true,
  scope_clarity_score: true,
  created_at: true,
}).extend({
  description_preview: z.string().max(200),
});

export const ListOpenTasksResponseSchema = z.object({
  tasks: z.array(TaskSummarySchema),
  total_open: z.number().int().nonnegative(),
  /** 任務池是否告警（供 MCP client 顯示警示） */
  stockout_warning: z.boolean(),
});
