import type { InferencePort, InferenceRequest, InferenceResult, InferenceEvidence } from '@insignia/iios-contracts';

/** DI token for the AI inference port (P7). Tests inject the testkit FakeInference. */
export const INFERENCE_PORT = Symbol('INFERENCE_PORT');

/**
 * The `nest start` binding: a deterministic, golden, no-network inference provider
 * — the same split as `LocalDevPorts` vs the testkit fakes. Behaviour mirrors
 * `@insignia/iios-testkit`'s `FakeInference` (kept runtime-independent of testkit,
 * which is a dev dependency). A real provider via the Capability Broker replaces
 * this in P9.
 */
export class LocalDeterministicInference implements InferencePort {
  async infer(req: InferenceRequest): Promise<InferenceResult> {
    const text = req.text ?? '';
    const evidence: InferenceEvidence[] = [
      { sourceType: 'INTERACTION', sourceId: req.interactionId ?? 'unknown', relevanceScore: 1 },
    ];
    const tokensIn = text.length === 0 ? 0 : text.trim().split(/\s+/).length;
    const model =
      req.jobType === 'CLASSIFY' ? 'golden-classifier' : req.jobType === 'SUMMARIZE' ? 'golden-summarizer' : 'golden-extractor';
    const modelRun = {
      model,
      modelVersion: '1',
      promptVersion: 'p1',
      tokensIn,
      tokensOut: Math.max(1, Math.ceil(tokensIn / 4)),
      costUnits: Math.max(1, Math.ceil(text.length / 10)),
      latencyMs: 1,
    };

    if (req.jobType === 'CLASSIFY') {
      const flagTypes = this.flags(text);
      return {
        artifactType: 'CLASSIFICATION',
        content: { flags: flagTypes },
        confidence: flagTypes.length > 0 ? 0.9 : 0.95,
        explanation: flagTypes.length > 0 ? `flagged: ${flagTypes.join(', ')}` : 'no moderation concerns',
        claims: flagTypes.map((flagType) => ({
          claimType: 'MODERATION_FLAG' as const,
          claimJson: { flagType, explanation: `keyword rule matched for ${flagType}` },
          confidence: 0.9,
        })),
        evidence,
        modelRun,
      };
    }

    if (req.jobType === 'SUMMARIZE') {
      const first = (text.split(/[.!?]/)[0] ?? '').trim();
      return {
        artifactType: 'SUMMARY',
        content: { text: `[ai] ${first}`, sourceInteractionId: req.interactionId ?? null },
        confidence: 0.8,
        explanation: 'extractive first-sentence summary (golden)',
        claims: [],
        evidence,
        modelRun,
      };
    }

    const event = this.extractEvent(text);
    if (!event) {
      return { artifactType: 'EXTRACTION', content: { claims: [] }, confidence: 0, abstentionReason: 'NO_CLAIM', claims: [], evidence, modelRun };
    }
    return {
      artifactType: 'EXTRACTION',
      content: { claims: [event] },
      confidence: 0.7,
      explanation: 'candidate event extracted (unconfirmed)',
      claims: [{ claimType: 'EVENT', claimJson: event, confidence: 0.7 }],
      evidence,
      modelRun,
    };
  }

  private flags(text: string): string[] {
    const t = text.toLowerCase();
    const out: string[] = [];
    if (t.includes('party') || /\b(9|10|11)\s*pm\b/.test(t)) out.push('AFTER_HOURS_EVENT');
    if (t.includes('sale') || t.includes('promo') || t.includes('discount')) out.push('PROMOTION');
    return out;
  }

  private extractEvent(text: string): { title: string; when: string; certainty: string } | null {
    const t = text.toLowerCase();
    const timeMatch = t.match(/\b(9|10|11|12|[1-8])\s*(am|pm)\b/);
    if (t.includes('party') || t.includes('event') || t.includes('meeting') || timeMatch) {
      const title = t.includes('party') ? 'party' : t.includes('meeting') ? 'meeting' : 'event';
      return { title, when: timeMatch ? timeMatch[0] : 'unspecified', certainty: 'DISCUSSION' };
    }
    return null;
  }
}
