import { httpClient } from '@/lib/http-client'
import { appConfig } from '@/app/config/index'
import { ApiError, ApiErrorCode } from '@/lib/error-handler'
import {
  CveConfig,
  CveConfigResponse,
  CveConfigUpdateResponse,
  CveArtifactResponse,
  CveIssueListResponse,
  CveWorkbenchResponse,
} from '@/lib/types'

type CvePrReadinessResponse = {
  cve_id: string
  ready: boolean
  branches: Array<{
    branch: string
    fix_branch: string
    ready: boolean
    reason: string
  }>
}

function extractCveId(title: string): string {
  const match = title.match(/CVE-\d{4}-\d+/i)
  return match ? match[0].toUpperCase() : title.trim()
}

function buildTaskSetupConfig(setupConfig: CveConfig) {
  return {
    signer_name: setupConfig.signer_name,
    signer_email: setupConfig.signer_email,
    clone_dir: setupConfig.clone_dir,
    branches: setupConfig.branches,
    fork_repo_url: setupConfig.fork_repo_url,
    repo_url: setupConfig.repo_url,
  }
}

export function buildTaskMessage(
  action: 'cve-analysis' | 'cve-submit-pr',
  issueTitle: string,
  setupConfig: CveConfig,
  options?: {
    prReadyBranches?: Array<{
      branch: string
      fix_branch: string
    }>
  }
): string {
  const cveId = extractCveId(issueTitle)
  const setupConfigStr = JSON.stringify(buildTaskSetupConfig(setupConfig), null, 2)
  if (action === 'cve-analysis') {
    return `你需要完成一个CVE漏洞分析任务。
【任务信息】
- CVE编号:${cveId}
- 配置信息:${setupConfigStr}
【必须遵守的规则】
1. 只能使用 cvekit_mcp 提供的工具:parse_issue、setup_env、get_commits、analyze_branches、apply_patch
2. 按照以下顺序执行:
   parse_issue → setup_env → get_commits → analyze_branches →(必要时)apply_patch
3. 如果存在需要修复的分支,必须调用 apply_patch 逐个进行处理
4. 严禁调用任何 PR 提交相关工具(如 create_pr)
5. 不允许伪造任何工具结果或仓库状态
6. 如果任一步失败,立即停止,并返回:
   - status: "failed"
   - summary: 失败原因
7. 如果 get_commits 或其他关键步骤返回空结果,导致下一步无法继续,直接终止流程,不要重试
【输出要求】
最终返回一个markdown格式的总结,包含:
- status: "success" 或 "failed"
- affected_branches
- patched_branches
- failed_branches
- summary(漏洞分析与修复情况)

如果 status 为 "success",且 patched_branches 非空,必须在总结最后明确提示:
   "补丁已成功应用,可在右侧 CVE 面板中创建 PR。"
如果 status 为 "failed",或 patched_branches 为空,则不要输出任何创建 PR 的提示。
请直接开始执行,不要解释你的计划。
`
  } else {
    const createPrArgs = (options?.prReadyBranches || []).map(item => ({
      cve_id: cveId,
      branch: item.branch,
      clone_dir: setupConfig.clone_dir,
      fork_repo_url: setupConfig.fork_repo_url,
      repo_url: setupConfig.repo_url,
    }))
    const prReadyBranchesText = JSON.stringify(
      (options?.prReadyBranches || []).map(item => ({
        branch: item.branch,
        fix_branch: item.fix_branch,
      })),
      null,
      2
    )
    const createPrArgsText = JSON.stringify(createPrArgs, null, 2)
    return `
你需要完成一个CVE漏洞的PR提交任务。

【任务信息】
- CVE编号:${cveId}
- 配置信息:${setupConfigStr}
- 后端已确认可提交 PR 的本地修复分支:
${prReadyBranchesText}

【create_pr 参数清单】
${createPrArgsText}

【执行要求】
1. 仅使用 cvekit_mcp 的 create_pr 工具提交PR
2. 必须逐条使用上方“create_pr 参数清单”调用 create_pr,不要自行补全、猜测或改写参数
3. 不得重新执行漏洞分析流程(禁止调用 parse_issue、setup_env、get_commits、analyze_branches、apply_patch)
4. 若某条 create_pr 失败,记录失败原因后继续处理下一条,不得重试同一条
5. 不允许伪造任何工具调用结果

【输出要求】
最终返回一个markdown格式的简短总结,包含:
- status: "success" 或 "failed"
- pr_links(成功创建的PR链接列表)
- failed_branches(失败分支与原因)
- summary(结果说明)

请直接开始执行,不要解释过程。
`
  }
}

async function fetchIssuesFromApi(
  issueUrl: string,
  limit: number,
  query = ''
): Promise<CveIssueListResponse['items']> {
  let path = `/cve/issues?issue_url=${encodeURIComponent(issueUrl)}&limit=${limit}`
  if (query) {
    path = `/cve/issues/search?issue_url=${encodeURIComponent(issueUrl)}&query=${encodeURIComponent(query)}&limit=${limit}`
  }

  const controller = new AbortController()
  const timeoutId = setTimeout(() => controller.abort(), appConfig.api.timeout)
  const authToken = appConfig.auth.token

  try {
    const response = await fetch(`${appConfig.api.baseUrl}${path}`, {
      method: 'GET',
      headers: {
        Accept: 'application/json',
        ...(authToken ? { Authorization: `Bearer ${authToken}` } : {}),
      },
      signal: controller.signal,
    })

    const contentType = response.headers.get('content-type')
    const responseData = contentType?.includes('application/json')
      ? await response.json()
      : await response.text()

    if (!response.ok) {
      throw new ApiError(
        `HTTP Error: ${response.status} ${response.statusText}`,
        response.status === 401 ? ApiErrorCode.AUTH_ERROR : ApiErrorCode.SERVER_ERROR,
        response.status,
        responseData
      )
    }

    const items = (responseData as CveIssueListResponse).items
    if (!Array.isArray(items)) throw new Error('GitCode response is not an array')
    return items
  } finally {
    clearTimeout(timeoutId)
  }
}

class CveService {
  public async getConfig(): Promise<CveConfigResponse> {
    return httpClient.get<CveConfigResponse>('/cve/config')
  }

  public async updateConfig(payload: CveConfig): Promise<CveConfigUpdateResponse> {
    return httpClient.put<CveConfigUpdateResponse>('/cve/config', payload)
  }

  public async updateToken(token: string): Promise<CveConfigUpdateResponse> {
    return httpClient.put<CveConfigUpdateResponse>('/cve/token', undefined, {
      headers: {
        'X-GitCode-Token': token,
      },
    })
  }

  public async getIssues(issueUrl: string, limit = 20): Promise<CveIssueListResponse> {
    const safeLimit = Math.min(Math.max(1, limit || 20), 100)
    const items = await fetchIssuesFromApi(issueUrl, safeLimit)
    return { items: items.slice(0, safeLimit) }
  }

  public async searchIssues(
    issueUrl: string,
    query: string,
    limit = 20
  ): Promise<CveIssueListResponse> {
    const safeLimit = Math.min(Math.max(1, limit || 20), 100)
    const needle = query.trim().toLowerCase()
    if (!needle) return this.getIssues(issueUrl, safeLimit)
    const items = await fetchIssuesFromApi(issueUrl, Math.max(safeLimit, 50), needle)
    return { items: items.slice(0, safeLimit) }
  }

  public async getWorkbench(
    cveId: string,
    branches: string,
    cloneDir: string
  ): Promise<CveWorkbenchResponse> {
    const query = new URLSearchParams({
      cve_id: cveId,
      branches,
      clone_dir: cloneDir,
    })
    return httpClient.get<CveWorkbenchResponse>(`/cve/workbench?${query.toString()}`)
  }

  public async getPrReadiness(
    cveId: string,
    branches: string,
    cloneDir: string,
    issueNumber: number
  ): Promise<CvePrReadinessResponse> {
    const query = new URLSearchParams({
      cve_id: cveId,
      branches,
      clone_dir: cloneDir,
      issue_number: String(issueNumber),
    })
    return httpClient.get<CvePrReadinessResponse>(`/cve/pr-readiness?${query.toString()}`)
  }

  public async getArtifact(path: string): Promise<CveArtifactResponse> {
    const query = new URLSearchParams({ path })
    return httpClient.get<CveArtifactResponse>(`/cve/artifact?${query.toString()}`)
  }
}

export const cveService = new CveService()