/**
 * Admin reimbursements (legacy CI reimbursements/*).
 * Backend is expected under `/api/v1/administrator/reimbursements`.
 */
import { apiUrl } from '../lib/apiOrigin'
import { ApiHttpError, apiFetch, getStoredToken } from './http'

const BASE = '/api/v1/administrator/reimbursements'

export type ReimbursementUserOption = { id?: number | string; firstname?: string; lastname?: string }

export type BatchSummaryRow = Record<string, unknown>
export type BatchDetailPayload = {
  items?: Array<Record<string, unknown>>
  checks?: Array<Record<string, unknown>>
}

export type ReimbursementsIndexResponse = {
  schoolYears?: string[]
  users?: ReimbursementUserOption[]
  batchSummaries?: BatchSummaryRow[]
  batchDetails?: Record<string, BatchDetailPayload>
  donationBatch?: BatchSummaryRow | null
  donationDetails?: BatchDetailPayload
  batchAttachments?: Record<string, { receipts?: unknown[]; checks?: unknown[] }>
}

export async function fetchReimbursementsIndex(params?: {
  semester?: string
  status?: string
  school_year?: string
  user_id?: string
}): Promise<ReimbursementsIndexResponse> {
  const qs = new URLSearchParams()
  if (params?.semester) qs.set('semester', params.semester)
  if (params?.status) qs.set('status', params.status)
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.user_id) qs.set('user_id', params.user_id)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch(`${BASE}${suffix}`)
}

/** Opens CSV download in a new tab (authenticated GET → blob URL). */
export async function downloadReimbursementsExport(params?: {
  semester?: string
  status?: string
  school_year?: string
  user_id?: string
  type?: string
}): Promise<void> {
  const qs = new URLSearchParams()
  if (params?.semester) qs.set('semester', params.semester)
  if (params?.status) qs.set('status', params.status)
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.user_id) qs.set('user_id', params.user_id)
  if (params?.type) qs.set('type', params.type)
  const url = apiUrl(`${BASE}/export?${qs}`)
  const headers = new Headers({ Accept: 'text/csv,*/*' })
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(url, { headers })
  if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
  const blob = await res.blob()
  window.open(URL.createObjectURL(blob), '_blank', 'noopener')
}

export async function downloadBatchCsv(batchId: number | string): Promise<void> {
  const qs = new URLSearchParams({ batch_id: String(batchId) })
  const url = apiUrl(`${BASE}/batch/export?${qs}`)
  const headers = new Headers({ Accept: 'text/csv,*/*' })
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(url, { headers })
  if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
  const blob = await res.blob()
  window.open(URL.createObjectURL(blob), '_blank', 'noopener')
}

export async function postBatchEmail(formData: FormData): Promise<{ success?: boolean; message?: string }> {
  const headers = new Headers({ Accept: 'application/json' })
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(apiUrl(`${BASE}/batch/send`), { method: 'POST', headers, body: formData })
  const body: unknown = await res.json().catch(() => null)
  if (!res.ok) {
    const msg =
      typeof body === 'object' && body !== null && 'error' in body
        ? String((body as { error?: unknown }).error ?? '')
        : ''
    throw new ApiHttpError(msg || `HTTP ${res.status}`, res.status, body)
  }
  return body as { success?: boolean; message?: string }
}

export type UnderProcessingWorkspace = {
  pendingItems?: Array<Record<string, unknown>>
  itemsPayload?: Array<Record<string, unknown>>
  existingBatches?: Array<Record<string, unknown>>
  adminUsers?: Array<{ id?: number; firstname?: string; lastname?: string }>
}

export async function fetchUnderProcessingWorkspace(): Promise<UnderProcessingWorkspace> {
  return apiFetch(`${BASE}/under-processing`)
}

export async function createReimbursementBatch(): Promise<{
  success?: boolean
  batch_id?: number
  sequence?: number
  yearly_number?: number
  csrf_hash?: string
}> {
  const fd = new FormData()
  return postFormExpectJson(`${BASE}/batch/create`, fd)
}

async function postFormExpectJson(path: string, form: FormData): Promise<{ success?: boolean; error?: string; csrf_hash?: string; reimbursement_id?: number } & Record<string, unknown>> {
  const headers = new Headers({ Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest' })
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(apiUrl(path), { method: 'POST', headers, body: form })
  const body: unknown = await res.json().catch(() => ({}))
  const data = body as Record<string, unknown>
  if (!res.ok) {
    throw new ApiHttpError(String(data.error ?? `HTTP ${res.status}`), res.status, body)
  }
  if (data && typeof data === 'object' && 'success' in data && data.success === false) {
    throw new ApiHttpError(String(data.error ?? 'Request failed'), res.status, body)
  }
  return data as { success?: boolean; error?: string; csrf_hash?: string; reimbursement_id?: number }
}

export function postBatchUpdate(form: FormData) {
  return postFormExpectJson(`${BASE}/batch/update`, form)
}

export function postBatchLock(form: FormData) {
  return postFormExpectJson(`${BASE}/batch/lock`, form)
}

export function postAdminCheckUpload(form: FormData) {
  return postFormExpectJson(`${BASE}/batch/admin-file/upload`, form)
}

export function postMarkDonation(form: FormData) {
  return postFormExpectJson(`${BASE}/mark-donation`, form)
}

export type ReimbursementFormContext = {
  users?: ReimbursementUserOption[]
  expense_id?: number | string
  prefill_amount?: number | string
}

export async function fetchReimbursementCreateContext(search: {
  expense_id?: string
}): Promise<ReimbursementFormContext> {
  const qs = new URLSearchParams()
  if (search.expense_id) qs.set('expense_id', search.expense_id)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch(`${BASE}/create-context${suffix}`)
}

async function postMultipart(path: string, formData: FormData): Promise<{ ok?: boolean; message?: string }> {
  const headers = new Headers({ Accept: 'application/json' })
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(apiUrl(path), { method: 'POST', headers, body: formData })
  const body: unknown = await res.json().catch(() => null)
  if (!res.ok) {
    const msg =
      typeof body === 'object' && body !== null && 'message' in body
        ? String((body as { message?: unknown }).message ?? '')
        : ''
    throw new ApiHttpError(msg || `HTTP ${res.status}`, res.status, body)
  }
  return (body ?? {}) as { ok?: boolean; message?: string }
}

export async function createReimbursement(formData: FormData) {
  return postMultipart(`${BASE}`, formData)
}

export async function fetchReimbursementForEdit(id: number | string): Promise<{
  reimbursement?: Record<string, unknown>
  users?: ReimbursementUserOption[]
  receipt_url?: string | null
}> {
  return apiFetch(`${BASE}/${encodeURIComponent(String(id))}/edit-data`)
}

export async function updateReimbursement(id: number | string, formData: FormData) {
  return postMultipart(`${BASE}/${encodeURIComponent(String(id))}`, formData)
}
