// ruleEngine/rateMatrixRules.ts
import { RATE_TYPES, REQUIRED_RATE_TYPES, MATRIX_STATUS } from '@/constants/rateMatrixConstants';

interface RateEntry {
  rateType: string;
  entries: Array<Record<string, any>>;
}

interface ValidationRule {
  id: string;
  description: string;
  severity: 'error' | 'warning';
  validate: (data: any) => boolean;
  message: string;
}

export class RateMatrixRulesEngine {
  private rules: ValidationRule[] = [];

  constructor() {
    this.initializeRules();
  }

  private initializeRules() {
    // Rule 1: All rate types must be present
    this.rules.push({
      id: 'ALL_TYPES_REQUIRED',
      description: 'Verify all 13 rate types are included',
      severity: 'error',
      validate: (rateSections: RateEntry[]) => {
        const submittedTypes = rateSections.map(s => s.rateType);
        return REQUIRED_RATE_TYPES.every(type => submittedTypes.includes(type));
      },
      message: 'All 13 rate types must be included in the submission',
    });

    // Rule 2: Each rate type must have at least one entry
    this.rules.push({
      id: 'MINIMUM_ENTRIES',
      description: 'Each rate type requires at least one rate entry',
      severity: 'error',
      validate: (rateSections: RateEntry[]) => {
        return rateSections.every(section => section.entries.length > 0);
      },
      message: 'Each rate type must have at least one rate entry',
    });

    // Rule 3: Dates must be valid
    this.rules.push({
      id: 'VALID_DATES',
      description: 'Rate entries must have valid date ranges',
      severity: 'error',
      validate: (rateSections: RateEntry[]) => {
        return rateSections.every(section =>
          section.entries.every(entry => {
            if (!entry.validFrom) return false;
            if (entry.validTo && new Date(entry.validTo) <= new Date(entry.validFrom)) {
              return false;
            }
            return true;
          })
        );
      },
      message: 'All rate entries must have valid dates (Valid To must be after Valid From)',
    });

    // Rule 4: Rates must be non-negative
    this.rules.push({
      id: 'NON_NEGATIVE_RATES',
      description: 'All rate values must be non-negative',
      severity: 'error',
      validate: (rateSections: RateEntry[]) => {
        const numericFields = ['baseRate', 'ratePerMetricTon', 'ratePerKm', 
                               'ratePerTrip', 'ratePerDay', 'ratePerUnit'];
        
        return rateSections.every(section =>
          section.entries.every(entry => {
            return numericFields.every(field => {
              const value = entry[field];
              return value === undefined || value === '' || Number(value) >= 0;
            });
          })
        );
      },
      message: 'Rate values cannot be negative',
    });

    // Rule 5: Business rule - Demurrage free days should be reasonable
    this.rules.push({
      id: 'DEMURRAGE_FREE_DAYS',
      description: 'Demurrage free days should be between 0 and 30',
      severity: 'warning',
      validate: (rateSections: RateEntry[]) => {
        const demurrageSection = rateSections.find(
          s => s.rateType === RATE_TYPES.DEMURRAGE
        );
        if (!demurrageSection) return true;
        
        return demurrageSection.entries.every(entry => {
          const freeDays = Number(entry.freeDays);
          return !freeDays || (freeDays >= 0 && freeDays <= 30);
        });
      },
      message: 'Demurrage free days typically range from 0 to 30 days',
    });

    // Rule 6: Cancellation fee percentage should be 0-100
    this.rules.push({
      id: 'CANCELLATION_FEE_RANGE',
      description: 'Cancellation fee percentage must be between 0 and 100',
      severity: 'error',
      validate: (rateSections: RateEntry[]) => {
        const cancellationSection = rateSections.find(
          s => s.rateType === RATE_TYPES.CANCELLATION_FEE
        );
        if (!cancellationSection) return true;
        
        return cancellationSection.entries.every(entry => {
          const percentage = Number(entry.cancellationFeePercentage);
          return !percentage || (percentage >= 0 && percentage <= 100);
        });
      },
      message: 'Cancellation fee percentage must be between 0 and 100',
    });
  }

  validate(data: RateEntry[]) {
    const errors: Array<{ ruleId: string; message: string; severity: string }> = [];
    const warnings: Array<{ ruleId: string; message: string; severity: string }> = [];

    this.rules.forEach(rule => {
      if (!rule.validate(data)) {
        const issue = {
          ruleId: rule.id,
          message: rule.message,
          severity: rule.severity,
        };
        
        if (rule.severity === 'error') {
          errors.push(issue);
        } else {
          warnings.push(issue);
        }
      }
    });

    return {
      isValid: errors.length === 0,
      errors,
      warnings,
    };
  }

  // Check if matrix can transition to a new status
  canTransition(fromStatus: string, toStatus: string, userRole: string): boolean {
    const transitions: Record<string, Array<{ to: string; allowedRoles: string[] }>> = {
      [MATRIX_STATUS.DRAFT]: [
        { to: MATRIX_STATUS.PENDING_APPROVAL, allowedRoles: ['Director'] },
      ],
      [MATRIX_STATUS.PENDING_APPROVAL]: [
        { to: MATRIX_STATUS.ACTIVE, allowedRoles: ['Chief Executive'] },
        { to: MATRIX_STATUS.REJECTED, allowedRoles: ['Chief Executive'] },
      ],
    };

    const allowedTransitions = transitions[fromStatus] || [];
    const transition = allowedTransitions.find(t => t.to === toStatus);
    
    return transition ? transition.allowedRoles.includes(userRole) : false;
  }
}

export const rateMatrixRulesEngine = new RateMatrixRulesEngine();