import { api } from '../api/client'
import {
  listCopyMissionJobs,
  pickActiveCopyMissionAnalyzeJob,
  pickActiveCopyMissionMatrixJob,
  pickActiveCopyMissionReplicateJobs,
  pickActiveCopyMissionScanJob,
  replicateJobScanPostId,
} from './copyFlow'
import type { JobData } from '../types/api'
import { isActiveJobStatus } from './jobStatus'

const jobStorageKey = (missionId: string) => `haixun.copyMission.${missionId.trim()}.jobs`

type StoredMissionJobs = {
  analyzeJobId?: string
  scanJobId?: string
  matrixJobId?: string
  replicateJobIds?: Record<string, string>
}

export function rememberCopyMissionJobIds(missionId: string, patch: Partial<StoredMissionJobs>) {
  const id = missionId.trim()
  if (!id) return
  try {
    const next: StoredMissionJobs = { ...readStoredMissionJobIds(id), ...patch }
    if (!next.analyzeJobId?.trim()) delete next.analyzeJobId
    if (!next.scanJobId?.trim()) delete next.scanJobId
    if (!next.matrixJobId?.trim()) delete next.matrixJobId
    if (next.replicateJobIds) {
      const cleaned: Record<string, string> = {}
      for (const [postId, jobId] of Object.entries(next.replicateJobIds)) {
        if (postId.trim() && jobId.trim()) cleaned[postId.trim()] = jobId.trim()
      }
      next.replicateJobIds = Object.keys(cleaned).length ? cleaned : undefined
    }
    sessionStorage.setItem(jobStorageKey(id), JSON.stringify(next))
  } catch {
    // ignore
  }
}

export function rememberCopyMissionReplicateJobId(missionId: string, scanPostId: string, jobId: string) {
  const stored = readStoredMissionJobIds(missionId)
  rememberCopyMissionJobIds(missionId, {
    replicateJobIds: { ...(stored.replicateJobIds ?? {}), [scanPostId.trim()]: jobId.trim() },
  })
}

export function readStoredMissionJobIds(missionId: string): StoredMissionJobs {
  const id = missionId.trim()
  if (!id) return {}
  try {
    const raw = sessionStorage.getItem(jobStorageKey(id))
    if (!raw) return {}
    const parsed = JSON.parse(raw) as StoredMissionJobs
    return parsed && typeof parsed === 'object' ? parsed : {}
  } catch {
    return {}
  }
}

export function clearStoredMissionJobId(missionId: string, kind: 'analyze' | 'scan' | 'matrix') {
  if (kind === 'analyze') {
    rememberCopyMissionJobIds(missionId, { analyzeJobId: undefined })
  } else if (kind === 'scan') {
    rememberCopyMissionJobIds(missionId, { scanJobId: undefined })
  } else {
    rememberCopyMissionJobIds(missionId, { matrixJobId: undefined })
  }
}

export function clearStoredReplicateJobId(missionId: string, scanPostId: string) {
  const stored = readStoredMissionJobIds(missionId)
  const next = { ...(stored.replicateJobIds ?? {}) }
  delete next[scanPostId.trim()]
  rememberCopyMissionJobIds(missionId, { replicateJobIds: next })
}

async function fetchJobIfActive(jobId: string, templateType: string): Promise<JobData | null> {
  const id = jobId.trim()
  if (!id) return null
  try {
    const job = await api.get<JobData>(`/api/v1/jobs/${encodeURIComponent(id)}`, { auth: true })
    if (job.template_type !== templateType) return null
    return isActiveJobStatus(job.status) ? job : null
  } catch {
    return null
  }
}

export type CopyMissionJobsSnapshot = {
  analyzeJob: JobData | null
  scanJob: JobData | null
  matrixJob: JobData | null
  replicateJobs: JobData[]
  analyzeJobId: string | null
  scanJobId: string | null
  matrixJobId: string | null
  replicateJobIds: string[]
}

/** Restore in-flight jobs after refresh: list API → mission last scan → sessionStorage. */
export async function hydrateCopyMissionJobs(
  missionId: string,
  lastScanJobId?: string,
): Promise<CopyMissionJobsSnapshot> {
  const id = missionId.trim()
  const jobs = id ? await listCopyMissionJobs(id) : []
  let analyzeJob = pickActiveCopyMissionAnalyzeJob(jobs)
  let scanJob = pickActiveCopyMissionScanJob(jobs)
  let matrixJob = pickActiveCopyMissionMatrixJob(jobs)
  let replicateJobs = pickActiveCopyMissionReplicateJobs(jobs)

  const stored = readStoredMissionJobIds(id)

  if (!analyzeJob && stored.analyzeJobId) {
    analyzeJob = await fetchJobIfActive(stored.analyzeJobId, 'analyze-copy-mission')
  }
  if (!scanJob && lastScanJobId) {
    scanJob = await fetchJobIfActive(lastScanJobId, 'scan-viral')
  }
  if (!scanJob && stored.scanJobId) {
    scanJob = await fetchJobIfActive(stored.scanJobId, 'scan-viral')
  }
  if (!matrixJob && stored.matrixJobId) {
    matrixJob = await fetchJobIfActive(stored.matrixJobId, 'generate-copy-matrix')
  }

  const replicateByPost = new Map<string, JobData>()
  for (const job of replicateJobs) {
    const postId = replicateJobScanPostId(job)
    if (postId) replicateByPost.set(postId, job)
  }
  if (stored.replicateJobIds) {
    for (const [postId, jobId] of Object.entries(stored.replicateJobIds)) {
      if (replicateByPost.has(postId)) continue
      const job = await fetchJobIfActive(jobId, 'generate-copy-draft')
      if (job) replicateByPost.set(postId, job)
    }
  }
  replicateJobs = [...replicateByPost.values()]

  if (analyzeJob?.id) {
    rememberCopyMissionJobIds(id, { analyzeJobId: analyzeJob.id })
  } else if (stored.analyzeJobId) {
    clearStoredMissionJobId(id, 'analyze')
  }
  if (scanJob?.id) {
    rememberCopyMissionJobIds(id, { scanJobId: scanJob.id })
  } else if (stored.scanJobId) {
    clearStoredMissionJobId(id, 'scan')
  }
  if (matrixJob?.id) {
    rememberCopyMissionJobIds(id, { matrixJobId: matrixJob.id })
  } else if (stored.matrixJobId) {
    clearStoredMissionJobId(id, 'matrix')
  }

  const replicateJobIds: Record<string, string> = {}
  for (const job of replicateJobs) {
    const postId = replicateJobScanPostId(job)
    if (postId && job.id) replicateJobIds[postId] = job.id
  }
  if (Object.keys(replicateJobIds).length) {
    rememberCopyMissionJobIds(id, { replicateJobIds })
  } else if (stored.replicateJobIds) {
    rememberCopyMissionJobIds(id, { replicateJobIds: {} })
  }

  return {
    analyzeJob,
    scanJob,
    matrixJob,
    replicateJobs,
    analyzeJobId: analyzeJob?.id ?? null,
    scanJobId: scanJob?.id ?? null,
    matrixJobId: matrixJob?.id ?? null,
    replicateJobIds: replicateJobs.map((job) => job.id),
  }
}