// Filter model + predicate for the settlement grids (Amazon / eBay), modelled on
// PayJoe's transaction filter: free-text search, booking-date range with quick
// presets, Klassifikation checkboxes, match status and "matchrelevant" (only rows
// that need a Beleg — sales and refunds). Applied through AG Grid's external
// filter API so it composes with the column filters and row grouping.

export interface SettlementGridFilter {
  search: string
  dateFrom: string // yyyy-mm-dd or ''
  dateTo: string // yyyy-mm-dd or ''
  buckets: string[] // empty = all classifications
  match: 'all' | 'matched' | 'unmatched'
  matchRelevant: boolean
  // Lexoffice sync state (Amazon page). All three only ever look at rows that
  // reference an order — account fees / payout rows are neither "with" nor
  // "without" an invoice, so they drop out as soon as one of these is set.
  invoice: 'all' | 'with' | 'without' // internal invoice exists?
  lexoffice: 'all' | 'uploaded' | 'notUploaded' // invoice uploaded to lexoffice? (invoice rows only)
  csv: 'all' | 'exported' | 'notExported' // order marked as exported via settlement CSV? (matched rows only)
}

export const defaultSettlementGridFilter = (): SettlementGridFilter => ({
  search: '',
  dateFrom: '',
  dateTo: '',
  buckets: [],
  match: 'all',
  matchRelevant: false,
  invoice: 'all',
  lexoffice: 'all',
  csv: 'all'
})

export const settlementGridFilterActive = (f: SettlementGridFilter | null | undefined): boolean => {
  if (!f) return false
  return !!(
    f.dateFrom || f.dateTo || (f.buckets && f.buckets.length) || (f.match && f.match !== 'all') || f.matchRelevant ||
    (f.invoice && f.invoice !== 'all') || (f.lexoffice && f.lexoffice !== 'all') || (f.csv && f.csv !== 'all')
  )
}

const MATCH_RELEVANT_BUCKETS = new Set(['sale', 'refund'])

const isoDay = (value?: string) => {
  if (!value) return ''
  const d = new Date(value)
  if (isNaN(d.getTime())) return ''
  // Local calendar day — the date inputs are local too.
  const y = d.getFullYear()
  const m = String(d.getMonth() + 1).padStart(2, '0')
  const dd = String(d.getDate()).padStart(2, '0')
  return `${y}-${m}-${dd}`
}

// `classify` maps a row to its bucket key ('sale' | 'refund' | 'orderFee' | …),
// i.e. classifyAmazonRow / classifyEbayRow.
export const settlementRowPassesFilter = (
  row: any,
  f: SettlementGridFilter,
  classify: (row: any) => string
): boolean => {
  if (!row) return true
  if (f.dateFrom || f.dateTo) {
    const day = isoDay(row.postedDate)
    if (f.dateFrom && (!day || day < f.dateFrom)) return false
    if (f.dateTo && (!day || day > f.dateTo)) return false
  }
  const bucket = classify(row)
  if (f.buckets && f.buckets.length && !f.buckets.includes(bucket)) return false
  if (f.matchRelevant && !MATCH_RELEVANT_BUCKETS.has(bucket)) return false
  if (f.match && f.match !== 'all') {
    // Only rows that reference an order can be matched at all; account-level
    // fees and the payout row are neither "zugeordnet" nor "nicht zugeordnet".
    if (!row.orderId) return false
    if (f.match === 'matched' && !row.matched) return false
    if (f.match === 'unmatched' && row.matched) return false
  }
  if (f.invoice && f.invoice !== 'all') {
    if (!row.orderId) return false
    if (f.invoice === 'with' && !row.invoiceExists) return false
    if (f.invoice === 'without' && row.invoiceExists) return false
  }
  if (f.lexoffice && f.lexoffice !== 'all') {
    // Only rows WITH an invoice can be uploaded / not yet uploaded.
    if (!row.invoiceExists) return false
    if (f.lexoffice === 'uploaded' && !row.invoiceLexofficeUploaded) return false
    if (f.lexoffice === 'notUploaded' && row.invoiceLexofficeUploaded) return false
  }
  if (f.csv && f.csv !== 'all') {
    // The CSV marker lives on the internal order, so only matched rows qualify.
    if (!row.matched) return false
    if (f.csv === 'exported' && !row.csvExported) return false
    if (f.csv === 'notExported' && row.csvExported) return false
  }
  return true
}

export type SettlementDatePreset = 'thisWeek' | 'lastWeek' | 'last3Weeks' | 'thisMonth' | 'lastMonth' | 'last3Months'

export const SETTLEMENT_DATE_PRESETS: { key: SettlementDatePreset; label: string }[] = [
  { key: 'thisWeek', label: 'diese Woche' },
  { key: 'lastWeek', label: 'letzte Woche' },
  { key: 'last3Weeks', label: 'letzte 3 Wochen' },
  { key: 'thisMonth', label: 'dieser Monat' },
  { key: 'lastMonth', label: 'letzter Monat' },
  { key: 'last3Months', label: 'letzte 3 Monate' }
]

const fmt = (d: Date) => isoDay(d.toISOString())
const startOfWeek = (d: Date) => {
  const r = new Date(d.getFullYear(), d.getMonth(), d.getDate())
  const dow = (r.getDay() + 6) % 7 // Monday = 0
  r.setDate(r.getDate() - dow)
  return r
}
const addDays = (d: Date, n: number) => { const r = new Date(d); r.setDate(r.getDate() + n); return r }

export const settlementDatePreset = (key: SettlementDatePreset, now = new Date()): { dateFrom: string; dateTo: string } => {
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
  switch (key) {
    case 'thisWeek': {
      const s = startOfWeek(today)
      return { dateFrom: fmt(s), dateTo: fmt(addDays(s, 6)) }
    }
    case 'lastWeek': {
      const s = addDays(startOfWeek(today), -7)
      return { dateFrom: fmt(s), dateTo: fmt(addDays(s, 6)) }
    }
    case 'last3Weeks': {
      const s = addDays(startOfWeek(today), -14)
      return { dateFrom: fmt(s), dateTo: fmt(today) }
    }
    case 'thisMonth': {
      const s = new Date(today.getFullYear(), today.getMonth(), 1)
      const e = new Date(today.getFullYear(), today.getMonth() + 1, 0)
      return { dateFrom: fmt(s), dateTo: fmt(e) }
    }
    case 'lastMonth': {
      const s = new Date(today.getFullYear(), today.getMonth() - 1, 1)
      const e = new Date(today.getFullYear(), today.getMonth(), 0)
      return { dateFrom: fmt(s), dateTo: fmt(e) }
    }
    case 'last3Months': {
      const s = new Date(today.getFullYear(), today.getMonth() - 2, 1)
      return { dateFrom: fmt(s), dateTo: fmt(today) }
    }
  }
}
