/**
 * Pure helpers that turn the `allBusinesses` query nodes into flat rows for the
 * business management table. Kept free of React/urql imports so they are easy to unit test.
 */

import { countryNameByCode } from '../../helpers/countries.js';

export type BusinessRow = {
  id: string;
  name: string;
  hebrewName: string | null;
  governmentId: string | null;
  countryCode: string | null;
  city: string | null;
  zipCode: string | null;
  createdAt: Date | null;
  updatedAt: Date | null;
  // categorization
  sortCodeKey: number | null;
  sortCodeName: string | null;
  taxCategoryName: string | null;
  irsCode: number | null;
  pcn874RecordType: string | null;
  // extension tags
  isClient: boolean;
  isAdmin: boolean;
  isActive: boolean;
  // suggestion defaults
  suggestionDescription: string | null;
  suggestionTags: string[];
};

/** Usage counts merged into table rows once the lazy usage query resolves (null until loaded). */
export type BusinessUsageCounts = {
  totalTransactions: number | null;
  totalDocuments: number | null;
  totalMiscExpenses: number | null;
  totalLedgerRecords: number | null;
};

/** A business table row: the mapped business plus its (optionally loaded) usage counts. */
export type BusinessTableRow = BusinessRow & BusinessUsageCounts;

/** Extra handles passed to the table via `table.options.meta` and read by cells. */
export type BusinessTableMeta = {
  usageFetching?: boolean;
  refetchBusinesses?: () => void;
};

/** True once all four usage counts are known (loaded) and zero — the delete guard. */
export function isBusinessUnused(row: BusinessUsageCounts): boolean {
  return (
    row.totalTransactions === 0 &&
    row.totalDocuments === 0 &&
    row.totalMiscExpenses === 0 &&
    row.totalLedgerRecords === 0
  );
}

/** Minimal shape of an `allBusinesses` node consumed by the table (LtdFinancialEntity fields). */
type RawBusinessNode = {
  __typename?: string | null;
  id: string;
  name: string;
  hebrewName?: string | null;
  governmentId?: string | null;
  country?: { code?: string | null } | null;
  city?: string | null;
  zipCode?: string | null;
  // DateTime scalars arrive as ISO strings at runtime (no urql scalar exchange), even though
  // codegen types them as Date; accept both and parse below.
  createdAt?: string | Date | null;
  updatedAt?: string | Date | null;
  sortCode?: { key?: number | null; name?: string | null } | null;
  taxCategory?: { name?: string | null } | null;
  irsCode?: number | null;
  pcn874RecordType?: string | null;
  isClient?: boolean | null;
  isAdmin?: boolean | null;
  isActive?: boolean | null;
  suggestions?: {
    description?: string | null;
    tags?: ReadonlyArray<{ name?: string | null }> | null;
  } | null;
};

/** Parse an ISO string / Date into a Date, returning null for missing or malformed values. */
function parseValidDate(value: string | Date | null | undefined): Date | null {
  if (!value) {
    return null;
  }
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? null : date;
}

/** Keep only company businesses, map them to table rows and sort by name (case-insensitive). */
export function businessNodesToRows(nodes: readonly RawBusinessNode[]): BusinessRow[] {
  return nodes
    .filter(node => node.__typename === 'LtdFinancialEntity')
    .map(node => ({
      id: node.id,
      name: node.name,
      hebrewName: node.hebrewName ?? null,
      governmentId: node.governmentId ?? null,
      countryCode: node.country?.code ?? null,
      city: node.city ?? null,
      zipCode: node.zipCode ?? null,
      createdAt: parseValidDate(node.createdAt),
      updatedAt: parseValidDate(node.updatedAt),
      sortCodeKey: node.sortCode?.key ?? null,
      sortCodeName: node.sortCode?.name ?? null,
      taxCategoryName: node.taxCategory?.name ?? null,
      irsCode: node.irsCode ?? null,
      pcn874RecordType: node.pcn874RecordType ?? null,
      isClient: node.isClient ?? false,
      isAdmin: node.isAdmin ?? false,
      isActive: node.isActive ?? true,
      suggestionDescription: node.suggestions?.description ?? null,
      suggestionTags:
        node.suggestions?.tags?.map(tag => tag.name).filter((name): name is string => !!name) ?? [],
    }))
    .sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
}

/** Locality shown in the table: the country name resolved from the stored country code. */
export function formatLocality(row: Pick<BusinessRow, 'countryCode'>): string {
  return countryNameByCode(row.countryCode) ?? '';
}

/** Merge per-business usage counts (from the lazy usage query) into the table rows by id. */
export function mergeBusinessUsage(
  rows: readonly BusinessRow[],
  usage: readonly ({ businessId: string } & BusinessUsageCounts)[],
): BusinessTableRow[] {
  const byId = new Map<string, BusinessUsageCounts>();
  for (const entry of usage) {
    byId.set(entry.businessId, entry);
  }
  return rows.map(row => {
    const counts = byId.get(row.id);
    return {
      ...row,
      totalTransactions: counts?.totalTransactions ?? null,
      totalDocuments: counts?.totalDocuments ?? null,
      totalMiscExpenses: counts?.totalMiscExpenses ?? null,
      totalLedgerRecords: counts?.totalLedgerRecords ?? null,
    };
  });
}

/** Client-side filters applied over all business rows. */
export type BusinessRowFilters = {
  name: string;
  client: boolean;
  admin: boolean;
  inactive: boolean;
  unusedOnly: boolean;
  sortCode: string;
  taxCategory: string;
};

/** Filter rows by the extension-tag flags, usage and free-text sort-code / tax-category. */
export function filterBusinessRows(
  rows: readonly BusinessTableRow[],
  filters: BusinessRowFilters,
): BusinessTableRow[] {
  const name = filters.name.trim().toLowerCase();
  const sortCode = filters.sortCode.trim().toLowerCase();
  const taxCategory = filters.taxCategory.trim().toLowerCase();
  return rows.filter(row => {
    if (name && !`${row.name} ${row.hebrewName ?? ''}`.toLowerCase().includes(name)) {
      return false;
    }
    if (filters.client && !row.isClient) {
      return false;
    }
    if (filters.admin && !row.isAdmin) {
      return false;
    }
    if (filters.inactive && row.isActive) {
      return false;
    }
    if (filters.unusedOnly && !isBusinessUnused(row)) {
      return false;
    }
    if (sortCode) {
      const keyMatch = String(row.sortCodeKey ?? '').includes(sortCode);
      const nameMatch = (row.sortCodeName ?? '').toLowerCase().includes(sortCode);
      if (!keyMatch && !nameMatch) {
        return false;
      }
    }
    if (taxCategory && !(row.taxCategoryName ?? '').toLowerCase().includes(taxCategory)) {
      return false;
    }
    return true;
  });
}
