import { apiFetch } from './http'

export type SchoolYearStatus = 'draft' | 'active' | 'closed' | 'archived' | string

export type SchoolYearRecord = {
  id: number
  name: string
  start_date: string
  end_date: string
  status: SchoolYearStatus
  is_current: boolean
  isCurrent?: boolean
  closed_at?: string | null
  closed_by?: number | null
}

export type SchoolYearSummary = {
  school_year: SchoolYearRecord
  totals: {
    students_considered: number
    students_blocked: number
    parents_with_balances: number
    parents_with_positive_balance?: number
    net_balance_to_transfer: number
    net_balance_impact?: number
    total_positive_unpaid_balance?: number
    total_credit_balance?: number
  }
}

export type SchoolYearPromotionRow = {
  student_id: number
  student_name: string
  parent_id?: number | null
  current_grade?: string | null
  current_class?: string | null
  promotion_action: string
  target_grade?: string | null
  target_class?: string | null
  target_class_section_id?: number | null
  warnings?: string[]
  decision?: string | null
  score?: number | null
}

export type SchoolYearPromotionPreview = {
  rows: SchoolYearPromotionRow[]
  summary: {
    total_students: number
    promote: number
    repeat: number
    graduate: number
    transfer: number
    withdraw: number
    hold: number
  }
}

export type SchoolYearParentBalanceRow = {
  parent_id: number
  parent_name?: string | null
  student_names?: string[]
  old_unpaid_balance: number
  positive_unpaid_balance?: number
  credit_balance: number
  net_balance?: number
  amount_to_transfer: number
  positive_invoice_ids?: number[]
  credit_invoice_ids?: number[]
  source_invoice_ids?: number[]
  existing_transfer_conflict?: boolean
}

export type SchoolYearParentBalancePreview = {
  from_school_year?: string
  to_school_year?: string
  rows: SchoolYearParentBalanceRow[]
  summary: {
    parents_with_non_zero_balance: number
    parents_with_positive_balance?: number
    parents_with_credit_balance: number
    total_old_unpaid_balance: number
    total_positive_unpaid_balance?: number
    total_credit_balance: number
    net_balance_to_transfer: number
    net_balance_impact?: number
    existing_transfer_conflicts: number
  }
}

export type SchoolYearCloseValidation = {
  can_close: boolean
  errors: string[]
  warnings: string[]
  promotion_summary: SchoolYearPromotionPreview['summary']
  financial_summary: SchoolYearParentBalancePreview['summary']
}

export type SchoolYearClosePreview = {
  school_year: SchoolYearRecord
  validation: SchoolYearCloseValidation
  promotion_preview: SchoolYearPromotionPreview
  parent_balances: SchoolYearParentBalancePreview
}

export type SchoolYearCloseResult = {
  closed_school_year: SchoolYearRecord
  new_school_year: SchoolYearRecord
  promotion_counts?: Record<string, number>
  balance_counts?: Record<string, number>
}

export type SchoolYearClosingReport = {
  old_school_year?: SchoolYearRecord | null
  new_school_year?: SchoolYearRecord | null
  closed_by?: string | number | null
  closed_at?: string | null
  audit_reference?: string | null
  totals?: {
    students_promoted?: number
    students_repeated?: number
    students_graduated?: number
    students_transferred?: number
    students_withdrawn?: number
    parents_with_unpaid_balances?: number
    total_unpaid_balance_transferred?: number
    parents_with_credit_balances?: number
    total_credit_carried_or_reported?: number
    total_credit_transferred?: number
    net_balance_impact?: number
  }
  warnings?: string[]
}

export type SchoolYearBalanceTransferReportRow = {
  parent_id: number
  parent_name?: string | null
  old_school_year?: string | null
  new_school_year?: string | null
  source_invoice_ids?: Array<number | string>
  old_unpaid_amount?: number
  new_old_balance_invoice_id?: number | string | null
  transfer_status?: string | null
  transfer_date?: string | null
  created_by?: string | number | null
}

export type SchoolYearBalanceTransferReport = {
  school_year?: SchoolYearRecord | null
  rows: SchoolYearBalanceTransferReportRow[]
  summary?: {
    parent_count?: number
    total_transferred?: number
    total_credit?: number
  }
}

export type ParentStatementLine = {
  label: string
  amount: number
  source_school_year?: string | null
  invoice_id?: number | string | null
}

export type ParentStatement = {
  parent_id?: number | null
  parent_name?: string | null
  school_year?: SchoolYearRecord | string | null
  lines: ParentStatementLine[]
  opening_balance?: number
  current_balance?: number
}

export type SaveSchoolYearPayload = {
  name: string
  start_date: string
  end_date: string
}

export type CloseSchoolYearPayload = {
  new_school_year: SaveSchoolYearPayload
  promotion_rules?: {
    default_action?: string
    exceptions?: Array<{
      student_id: number
      action: string
      target_grade_id?: number | null
      target_class_section_id?: number | null
    }>
  }
  transfer_unpaid_balances?: boolean
  confirmation?: string
}

type ApiListResponse = {
  ok?: boolean
  data?: SchoolYearRecord[]
}

type ApiRecordResponse = {
  ok?: boolean
  data?: SchoolYearRecord
}

type ApiSummaryResponse = {
  ok?: boolean
  data?: SchoolYearSummary
}

type ApiValidationResponse = {
  ok?: boolean
  validation?: SchoolYearCloseValidation
}

type ApiPreviewResponse = {
  ok?: boolean
  data?: SchoolYearClosePreview
}

type ApiParentBalancesResponse = {
  ok?: boolean
  data?: SchoolYearParentBalancePreview
}

type ApiPromotionPreviewResponse = {
  ok?: boolean
  data?: SchoolYearPromotionPreview
}

type ApiCloseResponse = {
  ok?: boolean
  data?: SchoolYearCloseResult
}

type ApiClosingReportResponse = {
  ok?: boolean
  data?: SchoolYearClosingReport
}

type ApiBalanceTransferReportResponse = {
  ok?: boolean
  data?: SchoolYearBalanceTransferReport
}

type ApiParentStatementResponse = {
  ok?: boolean
  data?: ParentStatement
}

export async function fetchSchoolYears(): Promise<SchoolYearRecord[]> {
  const response = await apiFetch<ApiListResponse>('/api/v1/school-years')
  return response.data ?? []
}

export async function createSchoolYear(payload: SaveSchoolYearPayload): Promise<SchoolYearRecord> {
  const response = await apiFetch<ApiRecordResponse>('/api/v1/school-years', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  })

  if (!response.data) {
    throw new Error('School year creation returned no record.')
  }

  return response.data
}

export async function updateSchoolYear(
  schoolYear: string,
  payload: SaveSchoolYearPayload,
): Promise<SchoolYearRecord> {
  const response = await apiFetch<ApiRecordResponse>(
    `/api/v1/school-years/selected${selectedYearQuery(schoolYear)}`,
    {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: selectedYearBody(payload, schoolYear),
    },
  )

  if (!response.data) {
    throw new Error('School year update returned no record.')
  }

  return response.data
}

function selectedYearQuery(schoolYear: string, extras?: Record<string, string | undefined>): string {
  const query = new URLSearchParams()
  query.set('school_year', schoolYear)
  for (const [key, value] of Object.entries(extras ?? {})) {
    if (value) query.set(key, value)
  }
  return `?${query.toString()}`
}

function selectedYearBody(payload: object, schoolYear: string): string {
  return JSON.stringify({ ...payload, school_year: schoolYear })
}

export async function fetchSchoolYearSummary(schoolYear: string): Promise<SchoolYearSummary> {
  const response = await apiFetch<ApiSummaryResponse>(
    `/api/v1/school-years/summary${selectedYearQuery(schoolYear)}`,
  )
  if (!response.data) {
    throw new Error('School year summary returned no data.')
  }
  return response.data
}

export async function validateSchoolYearClose(
  schoolYear: string,
  payload: CloseSchoolYearPayload,
): Promise<SchoolYearCloseValidation> {
  const response = await apiFetch<ApiValidationResponse>(
    `/api/v1/school-years/validate-close${selectedYearQuery(schoolYear)}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: selectedYearBody(payload, schoolYear),
    },
  )

  if (!response.validation) {
    throw new Error('School year validation returned no payload.')
  }

  return response.validation
}

export async function previewSchoolYearClose(
  schoolYear: string,
  payload: CloseSchoolYearPayload,
): Promise<SchoolYearClosePreview> {
  const response = await apiFetch<ApiPreviewResponse>(
    `/api/v1/school-years/preview-close${selectedYearQuery(schoolYear)}`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: selectedYearBody(payload, schoolYear),
    },
  )

  if (!response.data) {
    throw new Error('School year close preview returned no payload.')
  }

  return response.data
}

export async function closeSchoolYear(
  schoolYear: string,
  payload: CloseSchoolYearPayload,
): Promise<SchoolYearCloseResult> {
  const response = await apiFetch<ApiCloseResponse>(`/api/v1/school-years/close${selectedYearQuery(schoolYear)}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: selectedYearBody(payload, schoolYear),
  })

  if (!response.data) {
    throw new Error('School year close returned no payload.')
  }

  return response.data
}

export async function reopenSchoolYear(schoolYear: string): Promise<SchoolYearRecord> {
  const response = await apiFetch<ApiRecordResponse>(`/api/v1/school-years/reopen${selectedYearQuery(schoolYear)}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ school_year: schoolYear }),
  })

  if (!response.data) {
    throw new Error('School year reopen returned no payload.')
  }

  return response.data
}

export async function fetchSchoolYearParentBalances(
  schoolYear: string,
  toSchoolYear?: string,
): Promise<SchoolYearParentBalancePreview> {
  const response = await apiFetch<ApiParentBalancesResponse>(
    `/api/v1/school-years/parent-balances${selectedYearQuery(schoolYear, { to_school_year: toSchoolYear })}`,
  )

  if (!response.data) {
    throw new Error('Parent balances preview returned no payload.')
  }

  return response.data
}

export async function fetchSchoolYearPromotionPreview(
  schoolYear: string,
  toSchoolYear?: string,
): Promise<SchoolYearPromotionPreview> {
  const response = await apiFetch<ApiPromotionPreviewResponse>(
    `/api/v1/school-years/promotion-preview${selectedYearQuery(schoolYear, { to_school_year: toSchoolYear })}`,
  )

  if (!response.data) {
    throw new Error('Promotion preview returned no payload.')
  }

  return response.data
}


export async function fetchSchoolYearClosingReport(
  schoolYear: string,
): Promise<SchoolYearClosingReport> {
  const response = await apiFetch<ApiClosingReportResponse>(
    `/api/v1/school-years/reports/closing${selectedYearQuery(schoolYear)}`,
  )

  if (!response.data) {
    throw new Error('School year closing report returned no payload.')
  }

  return response.data
}

export async function fetchSchoolYearBalanceTransferReport(
  schoolYear: string,
): Promise<SchoolYearBalanceTransferReport> {
  const response = await apiFetch<ApiBalanceTransferReportResponse>(
    `/api/v1/school-years/parent-balances${selectedYearQuery(schoolYear)}`,
  )

  if (!response.data) {
    throw new Error('School year balance transfer report returned no payload.')
  }

  return response.data
}

export async function fetchParentStatement(params: {
  schoolYear?: string | null
  parentId?: number | null
}): Promise<ParentStatement> {
  const query = new URLSearchParams()
  if (params.schoolYear) query.set('school_year', params.schoolYear)
  if (params.parentId != null) query.set('parent_id', String(params.parentId))

  const response = await apiFetch<ApiParentStatementResponse>(
    `/api/v1/parent/statements${query.toString() ? `?${query}` : ''}`,
  )

  if (!response.data) {
    throw new Error('Parent statement returned no payload.')
  }

  return response.data
}
