import type { TransactionLine, AccountType } from '@/types/accounting';

/**
 * Validate that total debits equal total credits (double-entry principle)
 */
export function validateDoubleEntry(lines: TransactionLine[]): {
  valid: boolean;
  totalDebit: number;
  totalCredit: number;
  difference: number;
} {
  const totalDebit = lines.reduce((sum, line) => sum + (line.debit || 0), 0);
  const totalCredit = lines.reduce((sum, line) => sum + (line.credit || 0), 0);
  const difference = Math.abs(totalDebit - totalCredit);

  // Allow for small floating point differences (< 0.01)
  const valid = difference < 0.01;

  return {
    valid,
    totalDebit,
    totalCredit,
    difference,
  };
}

/**
 * Calculate line balance (debit - credit)
 */
export function calculateLineBalance(line: TransactionLine): number {
  return (line.debit || 0) - (line.credit || 0);
}

/**
 * Get account type from account number (Danish standard)
 */
export function getAccountTypeFromNumber(accountNumber: string): AccountType {
  const num = parseInt(accountNumber, 10);

  if (num >= 1000 && num < 2000) return 'asset';
  if (num >= 2000 && num < 3000) return 'liability';
  if (num >= 3000 && num < 4000) return 'equity';
  if (num >= 4000 && num < 5000) return 'revenue';
  if (num >= 5000 && num < 6000) return 'cogs';
  if (num >= 6000 && num < 7000) return 'expense';
  if (num >= 7000 && num < 8000) return 'personnel';
  if (num >= 8000 && num < 9000) return 'financial';
  if (num >= 9000 && num < 10000) return 'extraordinary';

  return 'asset'; // Default fallback
}

/**
 * Get Danish name for account type
 */
export function getAccountTypeName(type: AccountType): string {
  const names: Record<AccountType, string> = {
    asset: 'Aktiver',
    liability: 'Passiver',
    equity: 'Egenkapital',
    revenue: 'Indtægter',
    cogs: 'Vareforbrug',
    expense: 'Driftsomkostninger',
    personnel: 'Personaleomkostninger',
    financial: 'Finansielle poster',
    extraordinary: 'Ekstraordinære poster',
  };
  return names[type];
}

/**
 * Get account number range for type
 */
export function getAccountNumberRange(type: AccountType): { min: number; max: number } {
  const ranges: Record<AccountType, { min: number; max: number }> = {
    asset: { min: 1000, max: 1999 },
    liability: { min: 2000, max: 2999 },
    equity: { min: 3000, max: 3999 },
    revenue: { min: 4000, max: 4999 },
    cogs: { min: 5000, max: 5999 },
    expense: { min: 6000, max: 6999 },
    personnel: { min: 7000, max: 7999 },
    financial: { min: 8000, max: 8999 },
    extraordinary: { min: 9000, max: 9999 },
  };
  return ranges[type];
}

/**
 * Check if account is a balance sheet account (remains between periods)
 */
export function isBalanceSheetAccount(type: AccountType): boolean {
  return ['asset', 'liability', 'equity'].includes(type);
}

/**
 * Check if account is an income statement account (resets each period)
 */
export function isIncomeStatementAccount(type: AccountType): boolean {
  return !isBalanceSheetAccount(type);
}

/**
 * Calculate normal balance direction for account type
 * Returns 'debit' or 'credit'
 */
export function getNormalBalance(type: AccountType): 'debit' | 'credit' {
  // Asset and expense accounts normally have debit balances
  // Liability, equity, and revenue accounts normally have credit balances
  switch (type) {
    case 'asset':
    case 'cogs':
    case 'expense':
    case 'personnel':
    case 'financial':
    case 'extraordinary':
      return 'debit';
    case 'liability':
    case 'equity':
    case 'revenue':
      return 'credit';
  }
}

/**
 * Danish VAT rates
 */
export const VAT_RATES = {
  standard: 0.25, // 25% standard rate
  reduced: 0, // No reduced rate in Denmark
  zero: 0, // Zero-rated (export, etc.)
} as const;

// Note: VAT calculation functions (calculateVATFromGross, calculateVATFromNet)
// are available from '@/lib/vatCodes' - use those to avoid duplication

/**
 * Standard Danish VAT codes
 */
export const VAT_CODES = {
  S25: { code: 'S25', name: 'Udgående moms 25%', rate: 0.25, type: 'output' },
  K25: { code: 'K25', name: 'Indgående moms 25%', rate: 0.25, type: 'input' },
  E0: { code: 'E0', name: 'EU-varekøb 0%', rate: 0, type: 'eu' },
  U0: { code: 'U0', name: 'Eksport 0%', rate: 0, type: 'export' },
  NONE: { code: 'NONE', name: 'Ingen moms', rate: 0, type: 'none' },
} as const;

/**
 * Generate next transaction number
 */
export function generateTransactionNumber(lastNumber: string | null, prefix: string = ''): string {
  if (!lastNumber) {
    return `${prefix}1`;
  }
  const numPart = lastNumber.replace(/\D/g, '');
  const nextNum = parseInt(numPart, 10) + 1;
  return `${prefix}${nextNum}`;
}

// =====================================================
// AUTO-BOOKING FUNCTIONS (Simple Booking)
// =====================================================

import type { VATCode } from '@/types/vat';
import { VAT_CODE_CONFIG, VAT_ACCOUNTS } from '@/lib/vatCodes';

/**
 * Bank transaction input for auto-booking
 */
export interface BankTransactionInput {
  id: string;
  date: string;
  amount: number; // Negative = expense, Positive = income
  description: string;
  counterparty?: string;
  bankAccountId: string;
  bankAccountNumber: string;
}

/**
 * Simple booking input (one bank transaction -> one contra account)
 */
export interface SimpleBookingInput {
  bankTransaction: BankTransactionInput;
  contraAccountId: string;
  contraAccountNumber: string;
  contraAccountName: string;
  vatCode: VATCode;
  description?: string;
}

/**
 * Split booking line (for distributing one bank transaction to multiple accounts)
 */
export interface SplitBookingLine {
  accountId: string;
  accountNumber: string;
  accountName: string;
  amount: number; // Gross amount for this line
  vatCode: VATCode;
  description?: string;
}

/**
 * Split booking input (one bank transaction -> multiple contra accounts)
 */
export interface SplitBookingInput {
  bankTransaction: BankTransactionInput;
  lines: SplitBookingLine[];
}

/**
 * Generated transaction line with all details
 */
export interface GeneratedTransactionLine {
  accountId: string;
  accountNumber: string;
  accountName: string;
  description: string;
  debit: number;
  credit: number;
  vatCode?: VATCode;
  vatAmount?: number;
}

/**
 * Generated transaction result
 */
export interface GeneratedTransaction {
  date: string;
  description: string;
  lines: GeneratedTransactionLine[];
  bankTransactionId: string;
  isValid: boolean;
  validationMessage?: string;
}

/**
 * Generate simple double-entry from bank transaction
 *
 * For expense (negative bank amount, e.g., -15.000 kr husleje):
 *   1. 6100 Husleje     Debit: 12.000 kr (net)
 *   2. 5610 Moms (ind)  Debit:  3.000 kr (25% VAT)
 *   3. 1000 Bank        Credit: 15.000 kr (gross)
 *
 * For income (positive bank amount, e.g., +15.625 kr salg):
 *   1. 1000 Bank        Debit: 15.625 kr (gross)
 *   2. 4000 Salg        Credit: 12.500 kr (net)
 *   3. 5710 Moms (udg)  Credit:  3.125 kr (25% VAT)
 */
export function generateSimpleDoubleEntry(input: SimpleBookingInput): GeneratedTransaction {
  const { bankTransaction, contraAccountId, contraAccountNumber, contraAccountName, vatCode } = input;
  const description = input.description || bankTransaction.description;
  const grossAmount = Math.abs(bankTransaction.amount);
  const isExpense = bankTransaction.amount < 0;

  const vatConfig = VAT_CODE_CONFIG[vatCode];
  const lines: GeneratedTransactionLine[] = [];

  // Calculate VAT if applicable
  // Note: Round net first, then calculate VAT as gross - net
  // This ensures net + vat = gross (no floating point drift)
  let netAmount = grossAmount;
  let vatAmount = 0;

  if (vatConfig.rate > 0) {
    const rawNet = grossAmount / (1 + vatConfig.rate);
    netAmount = Math.round(rawNet * 100) / 100;
    // Calculate VAT as difference to guarantee gross = net + vat
    vatAmount = Math.round((grossAmount - netAmount) * 100) / 100;
  }

  if (isExpense) {
    // Expense: Money leaving bank account
    // Contra account (expense) gets debited with net amount
    lines.push({
      accountId: contraAccountId,
      accountNumber: contraAccountNumber,
      accountName: contraAccountName,
      description,
      debit: netAmount,
      credit: 0,
      vatCode,
      vatAmount: vatConfig.rate > 0 ? vatAmount : undefined,
    });

    // VAT account (input VAT) gets debited if applicable
    if (vatAmount > 0 && vatConfig.deductible) {
      lines.push({
        accountId: `vat-input-${vatCode}`,
        accountNumber: VAT_ACCOUNTS.inputVAT,
        accountName: 'Indgaaende moms',
        description: `Moms: ${description}`,
        debit: vatAmount,
        credit: 0,
      });
    }

    // For reverse charge (EU purchases), also credit output VAT
    if (vatConfig.reverseCharge && vatAmount > 0) {
      const outputVatAccount = vatCode === 'EU_VARE' ? VAT_ACCOUNTS.euVAT : VAT_ACCOUNTS.outputVAT;
      lines.push({
        accountId: `vat-output-${vatCode}`,
        accountNumber: outputVatAccount,
        accountName: vatCode === 'EU_VARE' ? 'EU-moms (erhvervelse)' : 'Udgaaende moms',
        description: `Moms: ${description}`,
        debit: 0,
        credit: vatAmount,
      });
    }

    // Bank account gets credited with gross amount
    lines.push({
      accountId: bankTransaction.bankAccountId,
      accountNumber: bankTransaction.bankAccountNumber,
      accountName: 'Bank',
      description,
      debit: 0,
      credit: grossAmount,
    });
  } else {
    // Income: Money entering bank account
    // Bank account gets debited with gross amount
    lines.push({
      accountId: bankTransaction.bankAccountId,
      accountNumber: bankTransaction.bankAccountNumber,
      accountName: 'Bank',
      description,
      debit: grossAmount,
      credit: 0,
    });

    // Contra account (revenue) gets credited with net amount
    lines.push({
      accountId: contraAccountId,
      accountNumber: contraAccountNumber,
      accountName: contraAccountName,
      description,
      debit: 0,
      credit: netAmount,
      vatCode,
      vatAmount: vatConfig.rate > 0 ? vatAmount : undefined,
    });

    // VAT account (output VAT) gets credited if applicable
    if (vatAmount > 0 && vatConfig.type === 'output') {
      lines.push({
        accountId: 'vat-output',
        accountNumber: VAT_ACCOUNTS.outputVAT,
        accountName: 'Udgaaende moms',
        description: `Moms: ${description}`,
        debit: 0,
        credit: vatAmount,
      });
    }
  }

  // Validate double-entry
  const validation = validateDoubleEntry(
    lines.map((l) => ({ ...l, id: '', transactionId: '' }))
  );

  return {
    date: bankTransaction.date,
    description,
    lines,
    bankTransactionId: bankTransaction.id,
    isValid: validation.valid,
    validationMessage: validation.valid
      ? undefined
      : `Ubalance: Difference ${validation.difference.toFixed(2)} kr`,
  };
}

/**
 * Generate split double-entry from bank transaction
 * Distributes one bank transaction to multiple contra accounts
 */
export function generateSplitDoubleEntry(input: SplitBookingInput): GeneratedTransaction {
  const { bankTransaction, lines: splitLines } = input;
  const grossAmount = Math.abs(bankTransaction.amount);
  const isExpense = bankTransaction.amount < 0;

  const generatedLines: GeneratedTransactionLine[] = [];

  // Validate that split lines sum to bank transaction amount
  const splitTotal = splitLines.reduce((sum, line) => sum + Math.abs(line.amount), 0);
  if (Math.abs(splitTotal - grossAmount) > 0.01) {
    return {
      date: bankTransaction.date,
      description: bankTransaction.description,
      lines: [],
      bankTransactionId: bankTransaction.id,
      isValid: false,
      validationMessage: `Split-beloeb (${splitTotal.toFixed(2)} kr) matcher ikke banktransaktion (${grossAmount.toFixed(2)} kr)`,
    };
  }

  if (isExpense) {
    // Process each split line for expenses
    for (const splitLine of splitLines) {
      const vatConfig = VAT_CODE_CONFIG[splitLine.vatCode];
      const lineGross = Math.abs(splitLine.amount);
      let lineNet = lineGross;
      let lineVat = 0;

      // Round net first, then calculate VAT as gross - net
      // This ensures net + vat = gross (no floating point drift)
      if (vatConfig.rate > 0) {
        const rawNet = lineGross / (1 + vatConfig.rate);
        lineNet = Math.round(rawNet * 100) / 100;
        lineVat = Math.round((lineGross - lineNet) * 100) / 100;
      }

      const description = splitLine.description || bankTransaction.description;

      // Contra account (expense) gets debited with net amount
      generatedLines.push({
        accountId: splitLine.accountId,
        accountNumber: splitLine.accountNumber,
        accountName: splitLine.accountName,
        description,
        debit: lineNet,
        credit: 0,
        vatCode: splitLine.vatCode,
        vatAmount: lineVat > 0 ? lineVat : undefined,
      });

      // VAT account (input VAT) gets debited if applicable
      if (lineVat > 0 && vatConfig.deductible) {
        generatedLines.push({
          accountId: `vat-input-${splitLine.vatCode}`,
          accountNumber: VAT_ACCOUNTS.inputVAT,
          accountName: 'Indgaaende moms',
          description: `Moms: ${description}`,
          debit: lineVat,
          credit: 0,
        });
      }

      // For reverse charge, also credit output VAT
      if (vatConfig.reverseCharge && lineVat > 0) {
        const outputVatAccount = splitLine.vatCode === 'EU_VARE' ? VAT_ACCOUNTS.euVAT : VAT_ACCOUNTS.outputVAT;
        generatedLines.push({
          accountId: `vat-output-${splitLine.vatCode}`,
          accountNumber: outputVatAccount,
          accountName: splitLine.vatCode === 'EU_VARE' ? 'EU-moms (erhvervelse)' : 'Udgaaende moms',
          description: `Moms: ${description}`,
          debit: 0,
          credit: lineVat,
        });
      }
    }

    // Bank account gets credited with total gross amount
    generatedLines.push({
      accountId: bankTransaction.bankAccountId,
      accountNumber: bankTransaction.bankAccountNumber,
      accountName: 'Bank',
      description: bankTransaction.description,
      debit: 0,
      credit: grossAmount,
    });
  } else {
    // Income: Bank account gets debited first
    generatedLines.push({
      accountId: bankTransaction.bankAccountId,
      accountNumber: bankTransaction.bankAccountNumber,
      accountName: 'Bank',
      description: bankTransaction.description,
      debit: grossAmount,
      credit: 0,
    });

    // Process each split line for income
    for (const splitLine of splitLines) {
      const vatConfig = VAT_CODE_CONFIG[splitLine.vatCode];
      const lineGross = Math.abs(splitLine.amount);
      let lineNet = lineGross;
      let lineVat = 0;

      // Round net first, then calculate VAT as gross - net
      // This ensures net + vat = gross (no floating point drift)
      if (vatConfig.rate > 0) {
        const rawNet = lineGross / (1 + vatConfig.rate);
        lineNet = Math.round(rawNet * 100) / 100;
        lineVat = Math.round((lineGross - lineNet) * 100) / 100;
      }

      const description = splitLine.description || bankTransaction.description;

      // Contra account (revenue) gets credited with net amount
      generatedLines.push({
        accountId: splitLine.accountId,
        accountNumber: splitLine.accountNumber,
        accountName: splitLine.accountName,
        description,
        debit: 0,
        credit: lineNet,
        vatCode: splitLine.vatCode,
        vatAmount: lineVat > 0 ? lineVat : undefined,
      });

      // VAT account (output VAT) gets credited if applicable
      if (lineVat > 0 && vatConfig.type === 'output') {
        generatedLines.push({
          accountId: 'vat-output',
          accountNumber: VAT_ACCOUNTS.outputVAT,
          accountName: 'Udgaaende moms',
          description: `Moms: ${description}`,
          debit: 0,
          credit: lineVat,
        });
      }
    }
  }

  // Validate double-entry
  const validation = validateDoubleEntry(
    generatedLines.map((l) => ({ ...l, id: '', transactionId: '' }))
  );

  return {
    date: bankTransaction.date,
    description: bankTransaction.description,
    lines: generatedLines,
    bankTransactionId: bankTransaction.id,
    isValid: validation.valid,
    validationMessage: validation.valid
      ? undefined
      : `Ubalance: Difference ${validation.difference.toFixed(2)} kr`,
  };
}

/**
 * Get suggested VAT code based on account type
 */
export function getSuggestedVATCode(accountNumber: string, isExpense: boolean): VATCode {
  const accountType = getAccountTypeFromNumber(accountNumber);

  // Expenses typically use input VAT (K25)
  if (isExpense) {
    // Some expense types are typically VAT-exempt
    if (accountType === 'financial') return 'NONE';
    if (accountType === 'personnel') return 'NONE';
    return 'K25';
  }

  // Revenue typically uses output VAT (S25)
  if (accountType === 'revenue') {
    return 'S25';
  }

  return 'NONE';
}

/**
 * Consolidate generated lines by account
 * Combines lines with the same account to reduce line count
 */
export function consolidateTransactionLines(
  lines: GeneratedTransactionLine[]
): GeneratedTransactionLine[] {
  const consolidated: Map<string, GeneratedTransactionLine> = new Map();

  for (const line of lines) {
    const key = line.accountNumber;
    const existing = consolidated.get(key);

    if (existing) {
      existing.debit += line.debit;
      existing.credit += line.credit;
      // Append description if different
      if (line.description && !existing.description.includes(line.description)) {
        existing.description = `${existing.description}; ${line.description}`;
      }
    } else {
      consolidated.set(key, { ...line });
    }
  }

  // Filter out lines with zero amounts
  return Array.from(consolidated.values()).filter(
    (line) => line.debit > 0 || line.credit > 0
  );
}
