/**
 * Administrator payment / notifications / financial report API.
 * Paths mirror Laravel `/api/v1/administrator/...` conventions expected by the SPA.
 */
import { apiUrl } from '../lib/apiOrigin'
import { ApiHttpError, apiFetch, getStoredToken } from './http'

export type AdminNotificationRow = {
  id?: number
  title?: string
  message?: string
  priority?: string | number
  scheduled_at?: string
  expires_at?: string
  deleted_at?: string
  target_group?: string
  created_at?: string
  isExpired?: boolean
}

export async function fetchNotificationsDeleted(params?: {
  school_year?: string
  semester?: string
}): Promise<{ notifications: AdminNotificationRow[] }> {
  const qs = new URLSearchParams()
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.semester) qs.set('semester', params.semester)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch(`/api/v1/notifications/deleted${suffix}`)
}

export async function fetchNotificationsActive(params?: {
  target_group?: string
  school_year?: string
  semester?: string
}): Promise<{ notifications: AdminNotificationRow[] }> {
  const qs = new URLSearchParams()
  if (params?.target_group) qs.set('target_group', params.target_group)
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.semester) qs.set('semester', params.semester)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch(`/api/v1/notifications/active${suffix}`)
}

export async function restoreDeletedNotification(
  id: number | string,
): Promise<{ ok?: boolean; message?: string }> {
  return apiFetch(`/api/v1/notifications/${encodeURIComponent(String(id))}/restore`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({}),
  })
}

async function postMultipart<T>(path: string, formData: FormData): Promise<T> {
  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 T
}

export type ManualPayPageResponse = {
  ok?: boolean
  parent?: Record<string, unknown> | null
  students?: Array<Record<string, unknown>>
  payments?: Array<Record<string, unknown>>
  invoices?: Array<Record<string, unknown>>
  searchTermUsedInSearch?: string
  installmentEndYmd?: string
}

export async function fetchManualPayPage(params: {
  search_term: string
  page?: number | string
}): Promise<ManualPayPageResponse> {
  const qs = new URLSearchParams()
  qs.set('search_term', params.search_term)
  if (params.page != null) qs.set('page', String(params.page))
  return apiFetch(`/api/v1/finance/manual-pay/search?${qs}`)
}

type ManualPaySuggestRow = { id?: number | string; label?: string; email?: string; phone?: string }

export async function fetchManualPaySuggest(q: string): Promise<ManualPaySuggestRow[]> {
  const qs = new URLSearchParams({ q })
  const body = await apiFetch<{ items?: unknown[]; suggestions?: unknown[]; data?: unknown[] }>(
    `/api/v1/finance/manual-pay/suggest?${qs}`,
  )
  const raw = body.items ?? body.suggestions ?? body.data ?? []
  return Array.isArray(raw) ? (raw as ManualPaySuggestRow[]) : []
}

export async function submitManualPayUpdate(formData: FormData): Promise<{ ok?: boolean; message?: string }> {
  const invoiceId = String(formData.get('invoice_id') ?? '').trim()
  if (!invoiceId) {
    throw new ApiHttpError('Invoice is required.', 422, { errors: { invoice_id: ['Invoice is required.'] } })
  }
  const payload = new FormData()
  const amount = formData.get('amount') ?? formData.get('paid_amount')
  if (amount != null) payload.set('amount', String(amount))
  for (const [key, value] of formData.entries()) {
    if (key === 'invoice_id' || key === 'paid_amount') continue
    payload.append(key, value)
  }
  return postMultipart(`/api/v1/finance/manual-pay/invoices/${encodeURIComponent(invoiceId)}/payments`, payload)
}

export async function submitManualPayEdit(formData: FormData): Promise<{ ok?: boolean; message?: string }> {
  const paymentId = String(formData.get('payment_id') ?? '').trim()
  if (!paymentId) {
    throw new ApiHttpError('Payment is required.', 422, { errors: { payment_id: ['Payment is required.'] } })
  }
  formData.delete('payment_id')
  return apiFetch(`/api/v1/finance/manual-pay/payments/${encodeURIComponent(paymentId)}`, {
    method: 'PUT',
    body: formData,
  })
}

/** Authenticated URL for embedding or downloading check/card files (legacy CI: serveCheckFile). */
export function manualPayCheckFileUrl(tokenOrKey: string, mode: 'inline' | 'download'): string {
  const enc = encodeURIComponent(tokenOrKey)
  return `/api/v1/finance/manual-pay/files/${enc}?mode=${encodeURIComponent(mode)}`
}

export async function fetchAuthenticatedBlobUrl(apiPath: string): Promise<string> {
  const headers = new Headers({ Accept: '*/*' })
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(apiUrl(apiPath), { headers })
  if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
  const blob = await res.blob()
  return URL.createObjectURL(blob)
}

export type PaymentNotificationLogRow = Record<string, unknown>

export async function fetchPaymentNotificationLogs(params?: {
  from?: string
  to?: string
  type?: string
  school_year?: string
  semester?: string
}): Promise<{
  logs: PaymentNotificationLogRow[]
  parentsById?: Record<string, string>
  filters?: { from?: string; to?: string; type?: string }
}> {
  const qs = new URLSearchParams()
  if (params?.from) qs.set('from', params.from)
  if (params?.to) qs.set('to', params.to)
  if (params?.type) qs.set('type', params.type)
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.semester) qs.set('semester', params.semester)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch(`/api/v1/administrator/payments/notification-logs${suffix}`)
}

export type UnpaidParentRow = Record<string, unknown>

export async function fetchUnpaidParents(params?: {
  school_year?: string
  semester?: string
}): Promise<{ rows: UnpaidParentRow[]; school_year?: string; schoolYears?: string[] }> {
  const qs = new URLSearchParams()
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.semester) qs.set('semester', params.semester)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch<{
    rows?: UnpaidParentRow[]
    results?: UnpaidParentRow[]
    school_year?: string
    schoolYear?: string
    schoolYears?: string[]
  }>(`/api/v1/finance/unpaid-parents${suffix}`).then((body) => ({
    rows: body.rows ?? body.results ?? [],
    school_year: body.school_year ?? body.schoolYear,
    schoolYears: body.schoolYears ?? [],
  }))
}

export async function sendPaymentReminders(payload: {
  school_year: string
  parent_id?: number | string
  return_to?: string
}): Promise<{ ok?: boolean; message?: string }> {
  return apiFetch('/api/v1/administrator/payments/notifications/send', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  })
}

export type ParentPaymentsModalRow = Record<string, unknown>

export async function fetchParentPaymentsForModal(
  parentId: number | string,
): Promise<{ payments: ParentPaymentsModalRow[]; parentName?: string }> {
  return apiFetch(
    `/api/v1/administrator/payments/parent/${encodeURIComponent(String(parentId))}/payments-list`,
  )
}

export async function applyDiscountByCodeForStudent(payload: {
  student_id: number | string
  voucher_code: string
}): Promise<{ ok?: boolean; message?: string }> {
  return apiFetch('/api/v1/discounts/apply-by-code', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  })
}

export type ExtraChargeRow = Record<string, unknown>

export async function fetchExtraChargesPage(params?: {
  school_year?: string
  semester?: string
  page?: number | string
  parent_id?: number | string
}): Promise<{
  rows: ExtraChargeRow[]
  schoolYear?: string
  schoolYears?: string[]
  semester?: string
  parents?: Array<{ id: number; firstname?: string; lastname?: string }>
  pager?: { current_page?: number; last_page?: number }
}> {
  const qs = new URLSearchParams()
  if (params?.school_year) qs.set('school_year', params.school_year)
  if (params?.semester) qs.set('semester', params.semester)
  if (params?.page != null) qs.set('page', String(params.page))
  if (params?.parent_id != null) qs.set('parent_id', String(params.parent_id))
  const suffix = qs.toString() ? `?${qs}` : ''
  return Promise.all([
    apiFetch<{
      rows?: ExtraChargeRow[]
      school_year?: string
      semester?: string
      pager?: { current_page?: number; last_page?: number }
    }>(`/api/v1/extra-charges${suffix}`),
    apiFetch<{
      schoolYear?: string
      schoolYears?: string[]
      semester?: string
      parents?: Array<{ id: number; firstname?: string; lastname?: string }>
    }>('/api/v1/extra-charges/options'),
  ]).then(([list, options]) => ({
    rows: Array.isArray(list?.rows) ? list.rows : [],
    schoolYear: options?.schoolYear ?? list?.school_year,
    schoolYears: Array.isArray(options?.schoolYears) ? options.schoolYears : [],
    semester: options?.semester ?? list?.semester,
    parents: Array.isArray(options?.parents) ? options.parents : [],
    pager: list?.pager,
  }))
}

export async function fetchChargeInvoicesForParent(parentId: number | string): Promise<
  Array<{ id?: number; invoice_number?: string }>
> {
  const body = await apiFetch<{ results?: unknown[] }>(
    `/api/v1/extra-charges/invoices?parent_id=${encodeURIComponent(String(parentId))}`,
  )
  const raw = body.results
  return Array.isArray(raw) ? (raw as Array<{ id?: number; invoice_number?: string }>) : []
}

export async function submitExtraCharge(formData: FormData): Promise<{ ok?: boolean; message?: string }> {
  return postMultipart('/api/v1/extra-charges', formData)
}

export type FinancialDetailedJson = {
  ok?: boolean
  invoices?: Array<Record<string, unknown>>
  payments?: Array<Record<string, unknown>>
  refunds?: Array<Record<string, unknown>>
  discounts?: Array<Record<string, unknown>>
  paymentBreakdown?: Record<string, { cash?: number; credit?: number; check?: number }>
  paymentTotals?: {
    total_cash?: number
    total_credit?: number
    total_check?: number
    total_all?: number
  }
  expenses?: Array<{ category?: string; total_amount?: number }>
  reimbursements?: Array<{ status?: string; total_amount?: number }>
  eventFeesTotal?: number
}

function unwrapFinancialReport(
  body: FinancialDetailedJson & { report?: FinancialDetailedJson },
): FinancialDetailedJson {
  if (body && typeof body === 'object' && body.report && typeof body.report === 'object') {
    return body.report
  }
  return body
}

export async function fetchFinancialReportDetailed(params: {
  school_year?: string
  date_from?: string
  date_to?: string
}): Promise<FinancialDetailedJson> {
  const qs = new URLSearchParams()
  if (params.school_year) qs.set('school_year', params.school_year)
  if (params.date_from) qs.set('date_from', params.date_from)
  if (params.date_to) qs.set('date_to', params.date_to)
  qs.set('format', 'json')
  const body = await apiFetch<FinancialDetailedJson & { report?: FinancialDetailedJson }>(
    `/api/v1/finance/financial-report?${qs}`,
  )
  return unwrapFinancialReport(body)
}

export async function downloadFinancialReportCsv(params: {
  school_year?: string
  date_from?: string
  date_to?: string
}): Promise<void> {
  const qs = new URLSearchParams()
  if (params.school_year) qs.set('school_year', params.school_year)
  if (params.date_from) qs.set('date_from', params.date_from)
  if (params.date_to) qs.set('date_to', params.date_to)
  const path = `/api/v1/finance/financial-report/csv?${qs}`
  const headers = new Headers()
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(apiUrl(path), { headers })
  if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
  const blob = await res.blob()
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = 'financial-report.csv'
  a.click()
  URL.revokeObjectURL(url)
}

export type FinancialSummaryJson = {
  ok?: boolean
  schoolYear?: string
  totalCharges?: number
  totalEventFees?: number
  totalExtraCharges?: number
  totalDiscounts?: number
  totalRefunds?: number
  totalExpenses?: number
  totalReimbursements?: number
  donationToSchool?: number
  netAmount?: number
  amountCollected?: number
  totalUnpaid?: number
  totalPaid?: number
}

function unwrapFinancialSummary(
  body: FinancialSummaryJson & {
    summary?: FinancialSummaryJson
    schoolYears?: string[]
  },
): FinancialSummaryJson {
  const summary =
    body && typeof body === 'object' && body.summary && typeof body.summary === 'object'
      ? body.summary
      : body

  if (
    body &&
    typeof body === 'object' &&
    Array.isArray(body.schoolYears) &&
    !Array.isArray((summary as { schoolYears?: unknown }).schoolYears)
  ) {
    return {
      ...summary,
      schoolYears: body.schoolYears,
    } as FinancialSummaryJson
  }

  return summary
}

export async function fetchFinancialReportSummary(params: {
  school_year?: string
}): Promise<FinancialSummaryJson> {
  const qs = new URLSearchParams()
  if (params.school_year) qs.set('school_year', params.school_year)
  qs.set('format', 'json')
  const body = await apiFetch<
    FinancialSummaryJson & { summary?: FinancialSummaryJson; schoolYears?: string[] }
  >(`/api/v1/finance/financial-summary?${qs}`)
  return unwrapFinancialSummary(body)
}

export async function downloadFinancialSummaryPdf(params: { school_year?: string }): Promise<void> {
  const qs = new URLSearchParams()
  if (params.school_year) qs.set('school_year', params.school_year)
  const path = `/api/v1/finance/financial-report/pdf?${qs}`
  const headers = new Headers()
  const token = getStoredToken()
  if (token) headers.set('Authorization', `Bearer ${token}`)
  const res = await fetch(apiUrl(path), { headers })
  if (!res.ok) throw new ApiHttpError(`HTTP ${res.status}`, res.status, null)
  const raw = await res.blob()
  const blob = new Blob([await raw.arrayBuffer()], { type: 'application/pdf' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = 'financial-summary.pdf'
  a.click()
  URL.revokeObjectURL(url)
}

export type PaypalRedirectContext = {
  parentName?: string
  totalAmount?: string | number
  schoolId?: string | number
  currency?: string
  invoiceId?: string | number
}

export async function fetchPaypalPaymentContext(params: {
  invoice_id?: string
}): Promise<PaypalRedirectContext> {
  const qs = new URLSearchParams()
  if (params.invoice_id) qs.set('invoice_id', params.invoice_id)
  const suffix = qs.toString() ? `?${qs}` : ''
  return apiFetch(`/api/v1/parent/payment/paypal-context${suffix}`)
}
