import type {
  DebugEmlErrorCode,
  DebugEmlErrorResponse,
  DebugEmlSuperAgentRunResult,
  DebugEmlUploadInput,
} from '@/types/debugEml'
import { getStoredAccessToken } from '@/services/authSession'
import { isAuthSessionInvalidPayload, notifyUnauthorized } from '@/services/httpClient'

const apiBaseUrl = import.meta.env.VITE_API_BASE_URL ?? ''
const debugEmlEndpoint = '/api/system/debug/eml-superagent-runs'

export class DebugEmlUploadError extends Error {
  readonly status: number
  readonly errorCode: DebugEmlErrorCode
  readonly details: unknown

  constructor(message: string, status: number, errorCode: DebugEmlErrorCode, details: unknown) {
    super(message)
    this.name = 'DebugEmlUploadError'
    this.status = status
    this.errorCode = errorCode
    this.details = details
  }
}

export async function uploadDebugEmlSuperAgentRun(
  input: DebugEmlUploadInput,
): Promise<DebugEmlSuperAgentRunResult> {
  const form = new FormData()
  form.append('file', input.file)
  form.append('hotel_id', input.hotelId.trim())
  const runLabel = input.runLabel?.trim()
  if (runLabel) {
    form.append('run_label', runLabel)
  }

  const response = await fetch(`${apiBaseUrl}${debugEmlEndpoint}`, {
    method: 'POST',
    headers: buildUploadHeaders(input.debugUploadKey),
    body: form,
  })

  const payload = await readResponsePayload(response)
  if (!response.ok) {
    if (isAuthSessionInvalidPayload(payload)) {
      notifyUnauthorized()
    }
    const errorPayload = isDebugEmlErrorResponse(payload) ? payload : {}
    throw new DebugEmlUploadError(
      errorPayload.message || `Request failed with status ${response.status}`,
      response.status,
      errorPayload.error_code || 'DEBUG_EML_RUN_FAILED',
      payload,
    )
  }

  return normalizeDebugEmlResult(payload)
}

function buildUploadHeaders(debugUploadKey: string): Record<string, string> {
  const headers: Record<string, string> = {
    Accept: 'application/json',
    'X-TH-Hotel-Debug-Upload-Key': debugUploadKey.trim(),
  }
  const token = getStoredAccessToken()
  if (token) {
    headers.Authorization = `Bearer ${token}`
  }
  return headers
}

async function readResponsePayload(response: Response): Promise<unknown> {
  const contentType = response.headers.get('content-type') ?? ''
  if (!contentType.includes('application/json')) {
    return response.text()
  }
  return response.json()
}

function normalizeDebugEmlResult(payload: unknown): DebugEmlSuperAgentRunResult {
  const result = isRecord(payload) ? payload : {}
  return {
    debug_run_id: stringValue(result.debug_run_id),
    source_message_id: nullableStringValue(result.source_message_id),
    source_provider: nullableStringValue(result.source_provider),
    external_message_id: nullableStringValue(result.external_message_id),
    external_conversation_id: nullableStringValue(result.external_conversation_id),
    original_eml_oss_url: nullableStringValue(result.original_eml_oss_url),
    original_eml_sha256: nullableStringValue(result.original_eml_sha256),
    uploaded_media: Array.isArray(result.uploaded_media)
      ? result.uploaded_media.map(normalizeUploadedMedia)
      : [],
    html_body_with_oss_urls: nullableStringValue(result.html_body_with_oss_urls),
    html_body_sanitized: nullableStringValue(result.html_body_sanitized),
    html_sanitize_required:
      typeof result.html_sanitize_required === 'boolean' ? result.html_sanitize_required : null,
    html_render_mode: nullableStringValue(result.html_render_mode),
    agentbus_like_payload: isRecord(result.agentbus_like_payload) ? result.agentbus_like_payload : null,
    superagent_session_id: nullableStringValue(result.superagent_session_id),
    superagent_run_id: nullableStringValue(result.superagent_run_id),
    superagent_raw_answer: nullableStringValue(result.superagent_raw_answer),
    superagent_parsed_json: result.superagent_parsed_json ?? null,
    warnings: Array.isArray(result.warnings) ? result.warnings.filter(isString) : [],
    status: nullableStringValue(result.status),
  }
}

function normalizeUploadedMedia(value: unknown): DebugEmlSuperAgentRunResult['uploaded_media'][number] {
  const media = isRecord(value) ? value : {}
  return {
    media_type: nullableStringValue(media.media_type),
    file_name: nullableStringValue(media.file_name),
    content_type: nullableStringValue(media.content_type),
    size_bytes: typeof media.size_bytes === 'number' ? media.size_bytes : null,
    external_url: nullableStringValue(media.external_url),
    external_media_id: nullableStringValue(media.external_media_id),
    object_key: nullableStringValue(media.object_key),
  }
}

function isDebugEmlErrorResponse(value: unknown): value is DebugEmlErrorResponse {
  return isRecord(value) && (typeof value.error_code === 'string' || typeof value.message === 'string')
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value)
}

function isString(value: unknown): value is string {
  return typeof value === 'string'
}

function nullableStringValue(value: unknown): string | null {
  return typeof value === 'string' ? value : null
}

function stringValue(value: unknown): string {
  return typeof value === 'string' ? value : ''
}
