import refreshTokenHelper from "../../../utils/refreshTokenHelper"
import getTokenHelper from "../../../utils/getTokenHelper"
import forceLogoutHelper from "../../../utils/forceLogoutHelper"
import errorHandlingHelper from "../../../utils/errorHandlingHelper"
import { archiveUpload, isValidToken, loadUpload, planAccount, rememberBankAccountAlias, writeDay } from "../../../utils/banking/bankFileImport"

// POST /api/accounting/bank-file-import/import
// Body: { token, iban, days: ['2026-06-23', …], bankAccountId? }  — the client
// sends the days in small chunks (sequentially) so one request never outlives
// the proxy timeout. `bankAccountId` is the target the user picked in the
// preview when the file IBAN matches no iDempiere account; it is remembered
// per IBAN once a line was written.
// The plan is RECOMPUTED against live iDempiere data right before writing, so a
// booking that arrived in the meantime (EBICS fetch, second browser tab) is
// still recognised as a duplicate. Statements are created Drafted.
const MAX_DAYS_PER_REQUEST = 10

const handleFunc = async (event: any, account: any, days: string[], sourceLabel: string, bankAccountId: number | null, authToken: any = null) => {
  const token = authToken ?? await getTokenHelper(event)
  const plan = await planAccount(event, token, account, days, bankAccountId)
  if (!plan.bankAccount) {
    return { status: 409, message: bankAccountId ? `Bankkonto ${bankAccountId} ist nicht (mehr) aktiv` : `Kein aktives iDempiere-Bankkonto mit IBAN ${account.iban} gefunden` }
  }
  const results = []
  // Oldest first — keeps DocumentNo order aligned with the balance chain.
  for (const day of plan.days) {
    results.push(await writeDay(event, token, plan, day, sourceLabel))
  }
  return { status: 200, bankAccount: plan.bankAccount, results }
}

export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  const uploadToken = String(body?.token || '')
  if (!isValidToken(uploadToken)) return { status: 400, message: 'Ungültiges Upload-Token' }

  const parsed = await loadUpload(uploadToken)
  if (!parsed) return { status: 404, message: 'Upload nicht mehr vorhanden — bitte die Datei erneut hochladen' }

  const iban = String(body?.iban || '').replace(/\s+/g, '').toUpperCase()
  const account = parsed.accounts.find((acc: any) => acc.iban === iban) || (parsed.accounts.length === 1 && !iban ? parsed.accounts[0] : null)
  if (!account) return { status: 404, message: 'Konto nicht im Upload enthalten' }

  const days: string[] = Array.from(new Set(
    (Array.isArray(body?.days) ? body.days : []).map((d: any) => String(d)).filter((d: string) => /^\d{4}-\d{2}-\d{2}$/.test(d))
  )).sort() as string[]
  if (!days.length) return { status: 400, message: 'Keine Tage ausgewählt' }
  if (days.length > MAX_DAYS_PER_REQUEST) return { status: 400, message: `Maximal ${MAX_DAYS_PER_REQUEST} Tage pro Anfrage` }

  const sourceLabel = parsed.files.length === 1 ? (parsed.files[0] || 'upload') : `${parsed.files[0] || 'upload'} +${parsed.files.length - 1}`
  const bankAccountId = Number(body?.bankAccountId || 0) || null

  let data: any = {}
  try {
    data = await handleFunc(event, account, days, sourceLabel, bankAccountId)
  } catch (err: any) {
    try {
      // Re-planning after the refresh is safe: days whose header already exists
      // come back as `resume`, already written lines as duplicates.
      let authToken: any = await refreshTokenHelper(event)
      data = await handleFunc(event, account, days, sourceLabel, bankAccountId, authToken)
    } catch (error: any) {
      data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
      forceLogoutHelper(event, data)
    }
  }

  if (Number(data?.status) === 200 && (data.results || []).some((r: any) => r.linesCreated > 0)) {
    await archiveUpload(uploadToken, account.iban)
    if (bankAccountId) await rememberBankAccountAlias(account.iban, bankAccountId)
  }
  return data
})
