/**
 * Fairness Orchestration Engine Client
 * This is a client-side wrapper that would call the API in production
 */

export interface OutputType {
  id: string;
  name: string;
  weight: number;
  description: string;
}

export interface InputSpec {
  dataset: string;
  dateRange?: { start: string; end: string };
  filters?: Record<string, any>;
  sensitiveAttributes: string[];
  estimatedSize?: number;
}

export interface TimelineSpec {
  mode: 'now' | 'scheduled' | 'continuous';
  sla?: string;
  deadline?: string;
}

export interface OrchestrationRequest {
  input: InputSpec;
  outputs: string[];
  timeline: TimelineSpec;
}

export interface OrchestrationResult {
  totalLoad: number;
  inputLoad: number;
  outputLoad: number;
  estimatedTime: number;
  feasible: boolean;
  warnings: string[];
  suggestions: string[];
}

// Output type definitions
export const OUTPUT_TYPES: Record<string, OutputType> = {
  'fairness-audit-pdf': {
    id: 'fairness-audit-pdf',
    name: 'Fairness Audit PDF',
    weight: 2.5,
    description: 'Comprehensive fairness audit report in PDF format'
  },
  'metrics-export': {
    id: 'metrics-export',
    name: 'Metrics Export (SPD, TPR, FPR)',
    weight: 1.0,
    description: 'Statistical parity difference, true positive rate, false positive rate metrics'
  },
  'flagged-cases-csv': {
    id: 'flagged-cases-csv',
    name: 'Flagged Cases CSV',
    weight: 1.5,
    description: 'Export of cases flagged for potential bias issues'
  },
  'exec-summary-slides': {
    id: 'exec-summary-slides',
    name: 'Executive Summary Slide Pack',
    weight: 2.0,
    description: 'Executive presentation slides with key findings'
  },
  'detailed-report-json': {
    id: 'detailed-report-json',
    name: 'Detailed Report (JSON)',
    weight: 1.2,
    description: 'Machine-readable detailed fairness analysis'
  },
  'alerts-config': {
    id: 'alerts-config',
    name: 'Alert Configuration',
    weight: 0.8,
    description: 'Automated alert rules for ongoing monitoring'
  },
  'dashboard-export': {
    id: 'dashboard-export',
    name: 'Dashboard Export',
    weight: 1.8,
    description: 'Interactive dashboard with fairness metrics'
  },
  'compliance-report': {
    id: 'compliance-report',
    name: 'Compliance Report',
    weight: 2.2,
    description: 'Regulatory compliance documentation'
  }
};

const INPUT_PASS_MULTIPLIER = 2.0;
const TOTAL_LOAD_MULTIPLIER = 3.2;
const OUTPUT_TARGET_MULTIPLIER = 1.2;
const BASE_PROCESSING_RATE = 10;
const INPUT_PROCESSING_RATE = 15;
const OUTPUT_PROCESSING_RATE = 8;

export function calculateInputLoad(input: InputSpec): number {
  if (input.estimatedSize) {
    return input.estimatedSize;
  }

  let baseSize = 100;
  baseSize += input.sensitiveAttributes.length * 20;

  if (input.dateRange) {
    const start = new Date(input.dateRange.start);
    const end = new Date(input.dateRange.end);
    const days = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
    baseSize += days * 5;
  }

  if (input.filters) {
    baseSize += Object.keys(input.filters).length * 10;
  }

  return baseSize;
}

export function calculateOutputLoad(outputIds: string[]): number {
  return outputIds.reduce((total, outputId) => {
    const output = OUTPUT_TYPES[outputId];
    if (!output) return total;
    return total + output.weight;
  }, 0);
}

export function calculateTotalLoad(inputLoad: number, outputLoad: number): number {
  const inputPasses = inputLoad * INPUT_PASS_MULTIPLIER;
  return outputLoad + inputPasses;
}

export function estimateProcessingTime(totalLoad: number): number {
  const avgRate = (INPUT_PROCESSING_RATE + OUTPUT_PROCESSING_RATE) / 2;
  return totalLoad / avgRate;
}

function parseSLAToSeconds(sla: string): number {
  const match = sla.match(/(\d+)\s*(hour|hours|day|days|minute|minutes|min|mins|second|seconds|sec|secs)/i);
  if (!match) return 3600;

  const value = parseInt(match[1], 10);
  const unit = match[2].toLowerCase();

  const multipliers: Record<string, number> = {
    second: 1, seconds: 1, sec: 1, secs: 1,
    minute: 60, minutes: 60, min: 60, mins: 60,
    hour: 3600, hours: 3600,
    day: 86400, days: 86400
  };

  return value * (multipliers[unit] || 3600);
}

function formatTime(seconds: number): string {
  if (seconds < 60) return `${Math.ceil(seconds)} seconds`;
  if (seconds < 3600) return `${(seconds / 60).toFixed(1)} minutes`;
  if (seconds < 86400) return `${(seconds / 3600).toFixed(1)} hours`;
  return `${(seconds / 86400).toFixed(1)} days`;
}

export function checkFeasibility(
  totalLoad: number,
  estimatedTime: number,
  timeline: TimelineSpec
): { feasible: boolean; warnings: string[]; suggestions: string[] } {
  const warnings: string[] = [];
  const suggestions: string[] = [];

  let maxTimeSeconds: number | null = null;
  if (timeline.sla) {
    maxTimeSeconds = parseSLAToSeconds(timeline.sla);
  } else if (timeline.deadline) {
    const now = Date.now();
    const deadline = new Date(timeline.deadline).getTime();
    maxTimeSeconds = Math.max(0, (deadline - now) / 1000);
  }

  const inputLoad = totalLoad / TOTAL_LOAD_MULTIPLIER;
  const outputLoad = totalLoad - (inputLoad * INPUT_PASS_MULTIPLIER);
  const targetOutputLoad = inputLoad * OUTPUT_TARGET_MULTIPLIER;

  if (outputLoad > targetOutputLoad * 1.5) {
    warnings.push(
      `Output complexity (${outputLoad.toFixed(1)} units) is significantly higher than recommended (${targetOutputLoad.toFixed(1)} units)`
    );
    suggestions.push('Consider reducing the number of outputs or simplifying output requirements');
  }

  if (maxTimeSeconds !== null) {
    if (estimatedTime > maxTimeSeconds) {
      warnings.push(
        `Estimated processing time (${formatTime(estimatedTime)}) exceeds requested timeline (${formatTime(maxTimeSeconds)})`
      );
      suggestions.push(`Consider extending timeline to ${formatTime(estimatedTime * 1.2)} or reducing outputs`);
    } else if (estimatedTime > maxTimeSeconds * 0.8) {
      warnings.push(
        `Estimated processing time (${formatTime(estimatedTime)}) is close to timeline limit (${formatTime(maxTimeSeconds)})`
      );
      suggestions.push('Consider adding buffer time or reducing outputs for safety');
    }
  }

  const expectedTotalLoad = inputLoad * TOTAL_LOAD_MULTIPLIER;
  if (totalLoad > expectedTotalLoad * 1.3) {
    warnings.push(
      `Total process load (${totalLoad.toFixed(1)} units) is higher than expected (${expectedTotalLoad.toFixed(1)} units)`
    );
  }

  const feasible = warnings.length === 0 || warnings.every(w => !w.includes('exceeds'));

  return { feasible, warnings, suggestions };
}

export function orchestrate(request: OrchestrationRequest): OrchestrationResult {
  const inputLoad = calculateInputLoad(request.input);
  const outputLoad = calculateOutputLoad(request.outputs);
  const totalLoad = calculateTotalLoad(inputLoad, outputLoad);
  const estimatedTime = estimateProcessingTime(totalLoad);

  const { feasible, warnings, suggestions } = checkFeasibility(
    totalLoad,
    estimatedTime,
    request.timeline
  );

  return {
    totalLoad,
    inputLoad,
    outputLoad,
    estimatedTime,
    feasible,
    warnings,
    suggestions
  };
}

export function getUserMessage(result: OrchestrationResult, request: OrchestrationRequest): string {
  const { inputLoad, outputLoad, estimatedTime, feasible, warnings } = result;

  if (feasible && warnings.length === 0) {
    return `This fairness audit will process approximately ${inputLoad.toFixed(0)} input units and generate ${outputLoad.toFixed(1)} output units, taking approximately ${formatTime(estimatedTime)} to complete.`;
  }

  if (feasible) {
    return `This audit is feasible but has some considerations: ${warnings.join('; ')}. Estimated time: ${formatTime(estimatedTime)}.`;
  }

  return `This audit configuration may not be feasible within the requested timeline. ${warnings.join('; ')}. Estimated time: ${formatTime(estimatedTime)}.`;
}

export function getAvailableOutputs(): OutputType[] {
  return Object.values(OUTPUT_TYPES);
}

export function getOutputType(id: string): OutputType | undefined {
  return OUTPUT_TYPES[id];
}

