/**
 * Custom XBRL concept mapping types for filling gaps in the standardized data loader.
 */

/**
 * XBRL concept reference in formulas.
 */
export interface ConceptReference {
  /** XBRL taxonomy namespace (e.g., "us-gaap", "ifrs-full") */
  taxonomy: string;
  /** Concept name within taxonomy */
  concept: string;
  /** Unit family for the concept value */
  unitFamily: UnitFamily;
}

/**
 * Formula mapping definition.
 */
export interface FormulaMapping {
  /** The formula expression string */
  expression: string;
  /** Whether this formula is valid (computed) */
  isValid?: boolean;
  /** Error message if validation failed (computed) */
  error?: string;
  /** Concept references found in the formula (computed) */
  conceptRefs?: ConceptReference[];
}

/**
 * Concept mapping variant.
 */
export interface ConceptMappingType {
  concept: CustomConcept;
  formula?: never;
}

/**
 * Formula mapping variant.
 */
export interface FormulaMappingType {
  concept?: never;
  formula: FormulaMapping;
}

/**
 * Discriminated union for mapping types.
 * This matches the Rust MappingKind enum serialization format.
 */
export type MappingType = ConceptMappingType | FormulaMappingType;

/**
 * Unit family for XBRL concepts.
 */
export type UnitFamily = 'currency' | 'currency_per_share' | 'shares' | 'pure';

/**
 * All available unit families.
 */
export const UNIT_FAMILIES: UnitFamily[] = ['currency', 'currency_per_share', 'shares', 'pure'];

/**
 * The target financial field for a custom mapping.
 */
export type TargetField =
  | 'total_revenues'
  | 'cost_of_sales'
  | 'gross_profit'
  | 'cash_and_equivalents'
  | 'short_term_investments'
  | 'accounts_receivable_net'
  | 'inventory'
  | 'other_current_assets'
  | 'total_current_assets'
  | 'property_plant_and_equipment_net'
  | 'goodwill'
  | 'intangible_assets'
  | 'other_non_current_assets'
  | 'total_assets'
  | 'accounts_payable'
  | 'accrued_expenses_and_other_current_liabilities'
  | 'short_term_debt'
  | 'total_current_liabilities'
  | 'long_term_debt'
  | 'other_non_current_liabilities'
  | 'total_liabilities'
  | 'retained_earnings'
  | 'accumulated_other_comprehensive_income_loss'
  | 'total_equity'
  | 'selling_general_and_administrative'
  | 'research_and_development'
  | 'other_operating_expenses'
  | 'operating_profit'
  | 'net_income'
  | 'net_income_attributable_to_common_shareholders'
  | 'non_operating_income'
  | 'total_non_operating_income'
  | 'income_before_provision_for_income_taxes'
  | 'provision_for_income_taxes'
  | 'basic_eps'
  | 'diluted_eps'
  | 'basic_weighted_average_shares_outstanding'
  | 'total_shares_outstanding'
  | 'diluted_weighted_average_shares_outstanding'
  | 'ebitda'
  | 'effective_tax_rate'
  | 'free_cash_flow'
  | 'capital_expenditure'
  | 'operating_cash_flow'
  | 'investing_cash_flow'
  | 'financing_cash_flow';

/**
 * Display names for target fields.
 */
export const TARGET_FIELD_DISPLAY_NAMES: Record<TargetField, string> = {
  total_revenues: 'Total Revenues',
  cost_of_sales: 'Cost of Sales',
  gross_profit: 'Gross Profit',
  cash_and_equivalents: 'Cash & Equivalents',
  short_term_investments: 'Short-Term Investments',
  accounts_receivable_net: 'Accounts Receivable, Net',
  inventory: 'Inventory',
  other_current_assets: 'Other Current Assets',
  total_current_assets: 'Total Current Assets',
  property_plant_and_equipment_net: 'Property, Plant & Equipment, Net',
  goodwill: 'Goodwill',
  intangible_assets: 'Intangible Assets',
  other_non_current_assets: 'Other Non-Current Assets',
  total_assets: 'Total Assets',
  accounts_payable: 'Accounts Payable',
  accrued_expenses_and_other_current_liabilities:
    'Accrued Expenses & Other Current Liabilities',
  short_term_debt: 'Short-Term Debt',
  total_current_liabilities: 'Total Current Liabilities',
  long_term_debt: 'Long-Term Debt',
  other_non_current_liabilities: 'Other Non-Current Liabilities',
  total_liabilities: 'Total Liabilities',
  retained_earnings: 'Retained Earnings',
  accumulated_other_comprehensive_income_loss:
    'Accumulated Other Comprehensive Income (Loss)',
  total_equity: 'Total Equity',
  selling_general_and_administrative: 'Selling, General & Administrative Expenses',
  research_and_development: 'Research & Development Expenses',
  other_operating_expenses: 'Other Operating Expenses',
  operating_profit: 'Operating Profit',
  net_income: 'Consolidated Net Income',
  net_income_attributable_to_common_shareholders: 'Net Income Attributable to Common Shareholders',
  non_operating_income: 'Non-Operating Income',
  total_non_operating_income: 'Total Non-Operating Income',
  income_before_provision_for_income_taxes: 'Income Before Provision for Income Taxes',
  provision_for_income_taxes: 'Provision for Income Taxes',
  basic_eps: 'Basic EPS',
  diluted_eps: 'Diluted EPS',
  basic_weighted_average_shares_outstanding: 'Basic Weighted Average Shares Outstanding',
  total_shares_outstanding: 'Total Shares Outstanding',
  diluted_weighted_average_shares_outstanding: 'Diluted Weighted Average Shares Outstanding',
  ebitda: 'EBITDA',
  effective_tax_rate: 'Effective Tax Rate',
  free_cash_flow: 'Free Cash Flow',
  capital_expenditure: 'Capital Expenditure',
  operating_cash_flow: 'Operating Cash Flow',
  investing_cash_flow: 'Investing Cash Flow',
  financing_cash_flow: 'Financing Cash Flow',
};

/**
 * A custom XBRL concept definition.
 */
export interface CustomConcept {
  /** The taxonomy namespace (e.g., "us-gaap", "ifrs-full", "xyz-custom") */
  taxonomy: string;
  /** The concept name within the taxonomy */
  concept: string;
  /** The unit family for this concept */
  unitFamily: UnitFamily;
}

/**
 * The scope of when a custom mapping applies.
 */
export interface MappingScope {
  /** Optional ticker symbol (e.g., "AAPL"). If empty, applies globally. */
  ticker?: string;
  /** Optional period start date (ISO format, e.g., "2023-01-01") */
  periodStart?: string;
  /** Optional period end date (ISO format, e.g., "2023-12-31") */
  periodEnd?: string;
}

/**
 * A custom XBRL concept mapping that overrides or extends standard concept mappings.
 */
export interface CustomXbrlConceptMapping {
  /** Unique identifier for this mapping */
  id: string;
  /** The target field this mapping applies to */
  targetField: TargetField;
  /** The mapping type (concept or formula) */
  mappingKind: MappingType;
  /** Scope of when this mapping applies (ticker, period) */
  scope: MappingScope;
  /** Whether this mapping is currently enabled */
  enabled: boolean;
  /** Optional user notes about why this mapping exists */
  notes?: string;
}

/**
 * The configuration container for all custom mappings.
 */
export interface MappingsConfig {
  /** Configuration version for migrations */
  version: number;
  /** ISO timestamp of last update */
  lastUpdated: string;
  /** All custom mappings */
  mappings: CustomXbrlConceptMapping[];
}

export type MappingChangeKind =
  | 'created'
  | 'updated'
  | 'deleted'
  | 'toggled'
  | 'imported';

/**
 * Result of formula validation.
 */
export interface FormulaValidationResult {
  /** Whether the formula is valid */
  isValid: boolean;
  /** Error message if invalid */
  error?: string;
  /** Field references found in the formula */
  fieldRefs?: TargetField[];
  /** Concept references found in the formula */
  conceptRefs?: ConceptReference[];
  /** Functions used in the formula */
  functions?: string[];
}

/**
 * Token for syntax highlighting.
 */
export interface FormulaToken {
  type: 'fieldRef' | 'conceptRef' | 'number' | 'operator' | 'paren' | 'function' | 'comma' | 'error';
  value: string;
  startPos: number;
  endPos: number;
}

export interface MappingRefreshScope {
  /** Whether every open earnings panel should refresh. */
  fullRefresh: boolean;
  /** Mapping scopes that may affect panel selection. */
  affectedScopes: MappingScope[];
  /** Informational list of changed targets. */
  affectedTargets: TargetField[];
}

export interface MappingsUpdatedEvent {
  changeKind: MappingChangeKind;
  refreshScope: MappingRefreshScope;
}

/**
 * Helper function to create a new mapping object.
 */
export function createMapping(
  targetField: TargetField,
  customConcept: CustomConcept,
  scope: MappingScope,
  notes?: string
): CustomXbrlConceptMapping {
  return {
    id: crypto.randomUUID(),
    targetField,
    mappingKind: { concept: customConcept },
    scope,
    enabled: true,
    notes,
  };
}

/**
 * Helper function to create a new formula mapping object.
 */
export function createFormulaMapping(
  targetField: TargetField,
  formulaExpression: string,
  scope: MappingScope,
  notes?: string
): CustomXbrlConceptMapping {
  return {
    id: crypto.randomUUID(),
    targetField,
    mappingKind: { formula: { expression: formulaExpression } },
    scope,
    enabled: true,
    notes,
  };
}

/**
 * Helper function to check if a mapping applies to a specific ticker and period.
 */
export function mappingAppliesToContext(
  mapping: CustomXbrlConceptMapping,
  ticker: string,
  periodDate: string
): boolean {
  if (!mapping.enabled) {
    return false;
  }

  // Check ticker
  if (mapping.scope.ticker && mapping.scope.ticker.toUpperCase() !== ticker.toUpperCase()) {
    return false;
  }

  // Check period
  const date = new Date(periodDate);
  if (isNaN(date.getTime())) {
    return false;
  }

  if (mapping.scope.periodStart) {
    const startDate = new Date(mapping.scope.periodStart);
    if (isNaN(startDate.getTime()) || date < startDate) {
      return false;
    }
  }

  if (mapping.scope.periodEnd) {
    const endDate = new Date(mapping.scope.periodEnd);
    if (isNaN(endDate.getTime()) || date > endDate) {
      return false;
    }
  }

  return true;
}

/**
 * Check if a mapping is a formula mapping.
 */
export function isFormulaMapping(mapping: CustomXbrlConceptMapping): boolean {
  return 'formula' in mapping.mappingKind && typeof mapping.mappingKind.formula !== 'undefined';
}

/**
 * Check if a mapping is a concept mapping.
 */
export function isConceptMapping(mapping: CustomXbrlConceptMapping): boolean {
  return 'concept' in mapping.mappingKind && typeof mapping.mappingKind.concept !== 'undefined';
}

/**
 * Get the custom concept from a mapping if it's a concept mapping.
 */
export function getCustomConcept(mapping: CustomXbrlConceptMapping): CustomConcept | null {
  if (isConceptMapping(mapping)) {
    return mapping.mappingKind.concept ?? null;
  }
  return null;
}

/**
 * Get the formula expression from a mapping if it's a formula mapping.
 */
export function getFormulaExpression(mapping: CustomXbrlConceptMapping): string | null {
  if (isFormulaMapping(mapping) && mapping.mappingKind.formula) {
    return mapping.mappingKind.formula.expression;
  }
  return null;
}

/**
 * Get all mappings that apply to a specific ticker and period.
 */
export function getApplicableMappings(
  mappings: CustomXbrlConceptMapping[],
  ticker: string,
  periodDate: string
): CustomXbrlConceptMapping[] {
  return mappings.filter((m) => mappingAppliesToContext(m, ticker, periodDate));
}

/**
 * Sort mappings by priority (highest first).
 * Priority: ticker+period > ticker-only > global
 */
export function sortMappingsByPriority(
  mappings: CustomXbrlConceptMapping[]
): CustomXbrlConceptMapping[] {
  return [...mappings].sort((a, b) => {
    const scoreA = calculateMappingPriorityScore(a);
    const scoreB = calculateMappingPriorityScore(b);
    return scoreB - scoreA; // Higher score first
  });
}

/**
 * Calculate a priority score for a mapping (higher = more specific).
 */
function calculateMappingPriorityScore(
  mapping: CustomXbrlConceptMapping
): number {
  let score = 0;

  // Ticker-specific is higher priority than global
  if (mapping.scope.ticker) {
    score += 100;
  }

  // Period constraints add specificity
  if (mapping.scope.periodStart) {
    score += 10;
  }
  if (mapping.scope.periodEnd) {
    score += 10;
  }

  return score;
}
