import { string } from 'alga-js'
import refreshTokenHelper from "../../utils/refreshTokenHelper"
import forceLogoutHelper from "../../utils/forceLogoutHelper"
import errorHandlingHelper from "../../utils/errorHandlingHelper"
import fetchHelper from "../../utils/fetchHelper"
import toIdempiereDate from "../../utils/idempiereDate"

// PayJoe API credentials
const PAYJOE_USERNAME = "info@logyou.de"
const PAYJOE_API_KEY = "!879sO4x$77Q"
const PAYJOE_ZUGANG_ID = 74724
const PAYJOE_API_URL = "https://api.payjoe.de/belegupload"

// Currency ISO codes mapping
const CURRENCY_ISO_CODES: Record<string, number> = {
  'EUR': 978,
  'USD': 840,
  'GBP': 826,
  'CHF': 756,
  'JPY': 392,
  'CAD': 124,
  'AUD': 36,
  'CNY': 156,
  'INR': 356,
  'PLN': 985,
  'SEK': 752,
  'NOK': 578,
  'DKK': 208,
  'CZK': 203,
  'HUF': 348,
  'RUB': 643,
  'TRY': 949,
  'BRL': 986,
  'MXN': 484,
  'ZAR': 710
}

const handleFunc = async (event: any, authToken: any = null) => {
  let data: any = {}
  const token = authToken ?? await getTokenHelper(event)
  const body = await readBody(event)
  const invoiceIds: number[] = body.ids || []

  if (!invoiceIds.length) {
    return {
      status: 400,
      message: 'No invoice IDs provided'
    }
  }

  // Fetch invoice details for all provided IDs
  const belege: any[] = []
  const errors: string[] = []
  const successIds: number[] = []

  for (const invoiceId of invoiceIds) {
    try {
      // Fetch invoice with partner and order details
      const invoice: any = await event.context.fetch(
        `models/c_invoice/${invoiceId}?$select=C_Invoice_ID,DocumentNo,DateInvoiced,GrandTotal,C_Currency_ID,C_BPartner_ID,C_Order_ID,DocBaseType,isUploadToPayJoe&$expand=C_BPartner_ID($select=Name,Name2,Value,EMail,C_BPartner_ID),C_Currency_ID($select=ISO_Code),C_Order_ID($select=ExternalOrderId)`,
        'GET',
        token,
        null
      )

      if (!invoice) {
        errors.push(`Invoice ${invoiceId} not found`)
        continue
      }

      // Check if already uploaded
      if (invoice.isUploadToPayJoe === true || invoice.isUploadToPayJoe === 'Y') {
        errors.push(`Invoice ${invoice.DocumentNo} already uploaded to PayJoe`)
        continue
      }

      // Determine Belegtyp: 0 = Rechnung (ARI), 1 = Gutschrift (ARC)
      let belegtyp = 0
      if (invoice.DocBaseType?.id === 'ARC' || invoice.DocBaseType?.identifier === 'ARC') {
        belegtyp = 1
      }

      // Get currency code
      const currencyIso = invoice.C_Currency_ID?.ISO_Code || 'EUR'
      const belegWaehrung = CURRENCY_ISO_CODES[currencyIso] || 978

      // Parse partner name into first/last name
      const partnerName = invoice.C_BPartner_ID?.Name || ''
      const partnerName2 = invoice.C_BPartner_ID?.Name2 || ''
      let vorname = ''
      let nachname = partnerName
      let firma = ''

      // If Name2 exists, assume Name is company and Name2 is contact
      if (partnerName2) {
        firma = partnerName
        const nameParts = partnerName2.split(' ')
        if (nameParts.length > 1) {
          vorname = nameParts[0]
          nachname = nameParts.slice(1).join(' ')
        } else {
          nachname = partnerName2
        }
      } else {
        // Try to split Name into first/last
        const nameParts = partnerName.split(' ')
        if (nameParts.length > 1) {
          vorname = nameParts[0]
          nachname = nameParts.slice(1).join(' ')
        }
      }

      const beleg = {
        BelegIDExtern: String(invoice.id).substring(0, 30),
        Belegdatum: invoice.DateInvoiced,
        Belegtyp: belegtyp,
        BelegBetrag: invoice.GrandTotal || 0,
        BelegWaehrung: belegWaehrung,
        BelegVorname: vorname.substring(0, 100),
        BelegNachname: nachname.substring(0, 100),
        BelegFirma: firma.substring(0, 100) || null,
        BelegKundenNr: (invoice.C_BPartner_ID?.Value || '').substring(0, 30),
        BelegEmail: (invoice.C_BPartner_ID?.EMail || '').substring(0, 100),
        BelegNummer: (invoice.DocumentNo || '').substring(0, 30),
        BelegExterneBestellNr: invoice.C_Order_ID?.ExternalOrderId ? String(invoice.C_Order_ID.ExternalOrderId).substring(0, 40) : null,
        BelegReferenz1: null,
        BelegReferenz2: null,
        BelegReferenz3: null,
        BelegReferenz4: null,
        BelegReferenz5: null,
        BelegReferenz6: null,
        BelegReferenz7: null,
        BelegReferenz8: null,
        BelegReferenz9: null,
        BelegReferenz10: null
      }

      belege.push({ beleg, invoiceId, documentNo: invoice.DocumentNo })
      successIds.push(invoiceId)
    } catch (err: any) {
      errors.push(`Error fetching invoice ${invoiceId}: ${err.message || 'Unknown error'}`)
    }
  }

  if (!belege.length) {
    return {
      status: 400,
      message: 'No valid invoices to upload',
      errors
    }
  }

  // Send to PayJoe API
  const payJoePayload = {
    UserName: PAYJOE_USERNAME,
    APIKey: PAYJOE_API_KEY,
    ZugangID: PAYJOE_ZUGANG_ID,
    Belege: belege.map(b => b.beleg)
  }

  try {
    const payJoeResponse: any = await $fetch(PAYJOE_API_URL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: payJoePayload
    })

    if (payJoeResponse?.Erfolgreich === true) {
      // Update invoices in iDempiere to mark as uploaded
      // (no milliseconds — iDempiere rejects ".123Z" datetimes)
      const uploadDate = toIdempiereDate(new Date())
      const updateErrors: string[] = []

      for (const { invoiceId, documentNo } of belege) {
        try {
          await fetchHelper(event, `models/c_invoice/${invoiceId}`, 'PUT', token, {
            isUploadToPayJoe: true,
            UploadDatePayJoe: uploadDate,
            tableName: 'C_Invoice'
          })
        } catch (updateErr: any) {
          updateErrors.push(`Failed to update invoice ${documentNo}: ${updateErr.message || 'Unknown error'}`)
        }
      }

      data = {
        status: 200,
        message: `Successfully uploaded ${belege.length} invoice(s) to PayJoe`,
        uploadedCount: belege.length,
        uploadDate: uploadDate,
        letztesBuchungsdatum: payJoeResponse.LetztesBuchungsdatum,
        errors: [...errors, ...updateErrors]
      }
    } else {
      data = {
        status: 500,
        message: 'PayJoe API returned unsuccessful response',
        payJoeResponse,
        errors
      }
    }
  } catch (payJoeErr: any) {
    data = {
      status: 500,
      message: `PayJoe API error: ${payJoeErr.message || 'Unknown error'}`,
      errors
    }
  }

  return data
}

export default defineEventHandler(async (event) => {
  let data: any = {}

  try {
    data = await handleFunc(event)
  } catch (err: any) {
    try {
      let authToken: any = await refreshTokenHelper(event)
      data = await handleFunc(event, authToken)
    } catch (error) {
      data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
      forceLogoutHelper(event, data)
    }
  }

  return data
})
