import {
  PropertySnapshot,
  ChangeDetectionResult,
  ChangeType,
  Severity,
  PropertyChange,
  DetectionConfig,
  Address,
} from './types';
import { matchRecords } from './matcher.service';

const DEFAULT_DETECTION_CONFIG: DetectionConfig = {
  ownershipNameThreshold: 0.7,
  deedDateSensitivity: 0.9,
  taxAmountChangePercent: 15,
};

function classifyFieldChange(field: string, oldValue: unknown, newValue: unknown, config: DetectionConfig): PropertyChange {
  let changeType: ChangeType;

  switch (field) {
    case 'ownerName':
      changeType =
        typeof oldValue === 'string' && typeof newValue === 'string'
          ? isSignificantNameChange(oldValue, newValue, config)
            ? 'ownership_transfer'
            : 'metadata_change'
          : 'ownership_transfer';
      break;
    case 'deedDate':
      changeType = 'deed_change';
      break;
    case 'taxAmount':
      changeType = 'tax_change';
      break;
    case 'lienCount':
      changeType = (newValue as number) > (oldValue as number) ? 'lien_filing' : 'metadata_change';
      break;
    case 'taxId':
      changeType = 'deed_change';
      break;
    default:
      changeType = 'metadata_change';
  }

  return { field, oldValue, newValue, changeType };
}

function isSignificantNameChange(oldName: string, newName: string, config: DetectionConfig): boolean {
  const dummyAddress: Address = {
    streetNumber: '0',
    streetName: 'dummy',
    city: 'dummy',
    state: 'XX',
    zip: '00000',
  };

  const result = matchRecords(oldName, dummyAddress, newName, dummyAddress);
  return result.nameScore < config.ownershipNameThreshold;
}

function determineSeverity(changes: PropertyChange[], config: DetectionConfig): Severity {
  const severityOverrides = config.severityOverrides || {};

  const typeToSeverity: Record<ChangeType, Severity> = {
    ownership_transfer: severityOverrides['ownership_transfer'] || 'major',
    deed_change: severityOverrides['deed_change'] || 'moderate',
    lien_filing: severityOverrides['lien_filing'] || 'moderate',
    tax_change: severityOverrides['tax_change'] || 'minor',
    metadata_change: severityOverrides['metadata_change'] || 'minor',
  };

  const severityOrder: Severity[] = ['major', 'moderate', 'minor'];

  for (const change of changes) {
    const sev = typeToSeverity[change.changeType];
    const idx = severityOrder.indexOf(sev);
    if (idx === 0) return 'major';
  }

  for (const change of changes) {
    const sev = typeToSeverity[change.changeType];
    if (sev === 'moderate') return 'moderate';
  }

  return 'minor';
}

function computeChangeConfidence(changes: PropertyChange[], config: DetectionConfig): number {
  if (changes.length === 0) return 0;

  let totalConfidence = 0;
  for (const change of changes) {
    switch (change.changeType) {
      case 'ownership_transfer':
        totalConfidence += 0.95;
        break;
      case 'deed_change':
        totalConfidence += config.deedDateSensitivity;
        break;
      case 'tax_change': {
        const oldVal = change.oldValue as number;
        const newVal = change.newValue as number;
        const pctChange = oldVal ? Math.abs(newVal - oldVal) / oldVal * 100 : 100;
        totalConfidence += pctChange >= config.taxAmountChangePercent ? 0.85 : 0.5;
        break;
      }
      case 'lien_filing':
        totalConfidence += 0.9;
        break;
      default:
        totalConfidence += 0.4;
    }
  }

  return Math.round((totalConfidence / changes.length) * 1000) / 1000;
}

export function detectChanges(
  previous: PropertySnapshot,
  current: PropertySnapshot,
  config?: Partial<DetectionConfig>,
): ChangeDetectionResult {
  const effectiveConfig = { ...DEFAULT_DETECTION_CONFIG, ...config };
  const changes: PropertyChange[] = [];

  const fieldsToCompare: (keyof Omit<PropertySnapshot, 'id' | 'capturedAt' | 'propertyId'>)[] = [
    'ownerName',
    'deedDate',
    'taxId',
    'taxAmount',
    'lienCount',
    'propertyType',
  ];

  for (const field of fieldsToCompare) {
    const oldValue = previous[field];
    const newValue = current[field];

    if (oldValue !== newValue) {
      changes.push(classifyFieldChange(field, oldValue, newValue, effectiveConfig));
    }
  }

  const addressChanges = detectAddressChanges(previous.address, current.address);
  changes.push(...addressChanges);

  const severity = determineSeverity(changes, effectiveConfig);
  const confidence = computeChangeConfidence(changes, effectiveConfig);

  let changeType: ChangeType = 'metadata_change';
  if (changes.some(c => c.changeType === 'ownership_transfer')) {
    changeType = 'ownership_transfer';
  } else if (changes.some(c => c.changeType === 'deed_change')) {
    changeType = 'deed_change';
  } else if (changes.some(c => c.changeType === 'lien_filing')) {
    changeType = 'lien_filing';
  } else if (changes.some(c => c.changeType === 'tax_change')) {
    changeType = 'tax_change';
  }

  return {
    propertyId: previous.propertyId,
    changeType,
    severity,
    confidence,
    changes,
    previousSnapshot: previous,
    currentSnapshot: current,
    detectedAt: new Date().toISOString(),
  };
}

function detectAddressChanges(oldAddr: Address, newAddr: Address): PropertyChange[] {
  const changes: PropertyChange[] = [];

  const addressFields: (keyof Address)[] = ['streetNumber', 'streetName', 'streetType', 'unit', 'city', 'state', 'zip'];

  for (const field of addressFields) {
    const oldVal = oldAddr[field];
    const newVal = newAddr[field];
    if (oldVal !== newVal) {
      changes.push({
        field: `address.${field}`,
        oldValue: oldVal,
        newValue: newVal,
        changeType: 'metadata_change',
      });
    }
  }

  return changes;
}

export function shouldTriggerAlert(result: ChangeDetectionResult, minSeverity: Severity = 'moderate'): boolean {
  const severityOrder: Severity[] = ['minor', 'moderate', 'major'];
  const resultIdx = severityOrder.indexOf(result.severity);
  const minIdx = severityOrder.indexOf(minSeverity);
  return resultIdx >= minIdx && result.confidence >= 0.7;
}

export { classifyFieldChange, determineSeverity, computeChangeConfidence };
