import type { BulkStringItem, BulkTranslateResponse, GeminiTranslationResponse, Tone } from '../types';
import { mockTranslationStore, MockTranslationStore } from './mockTranslationStore';
import {
  StructuredTranslationFields,
  StructuredTranslationResponse,
  TranslationProvider,
  TranslationProviderError,
  validateProviderResult,
} from './translationProvider';

export const MOCK_TRANSLATION_SCENARIOS = [
  'success',
  'pending_hold',
  'processing_hold',
  'rate_limited',
  'transient_failure',
  'permanent_failure',
  'timeout',
  'malformed_response',
] as const;

export type MockTranslationScenario = typeof MOCK_TRANSLATION_SCENARIOS[number];

export interface MockTranslationContext {
  jobId?: string;
  scenario?: MockTranslationScenario;
  attempt?: number;
  signal?: AbortSignal;
  abortSignal?: AbortSignal;
}

const MOCK_MODEL = 'mock-translator-v1';
const MOCK_INPUT_TOKENS = 7;
const MOCK_OUTPUT_TOKENS = 5;
const MOCK_TOKENS = MOCK_INPUT_TOKENS + MOCK_OUTPUT_TOKENS;

export class MockTranslationProvider implements TranslationProvider {
  private readonly store: MockTranslationStore;
  private readonly context: MockTranslationContext;

  constructor(store: MockTranslationStore = mockTranslationStore, context: MockTranslationContext = {}) {
    this.store = store;
    this.context = context;
  }

  async translate(
    content: string,
    _sourceLang: string,
    targetLang: string,
    _tone?: Tone,
    context?: MockTranslationContext
  ): Promise<GeminiTranslationResponse> {
    const active = this.resolveContext(context);
    const scenario = this.validateContext(active);
    await this.beforeCall(active, scenario);

    if (scenario === 'malformed_response') {
      return validateProviderResult('text', {
        translation: '',
        tokens_used: MOCK_TOKENS,
        input_tokens: MOCK_INPUT_TOKENS,
        output_tokens: MOCK_OUTPUT_TOKENS,
        processing_time_ms: 0,
        model_used: MOCK_MODEL,
      });
    }
    if (!isSuccessfulScenario(scenario)) throw scenarioError(scenario);

    return validateProviderResult('text', this.textResult(content, targetLang));
  }

  async translateBulk(
    strings: BulkStringItem[],
    _sourceLang: string,
    targetLang: string,
    _tone?: Tone,
    context?: MockTranslationContext
  ): Promise<BulkTranslateResponse> {
    const active = this.resolveContext(context);
    const scenario = this.validateContext(active);
    await this.beforeCall(active, scenario);

    if (scenario === 'malformed_response') {
      return validateProviderResult('bulk', {
        results: strings.map((item) => ({
          id: item.id,
          translation: '',
          success: true,
        })),
        tokens_used: MOCK_TOKENS,
        input_tokens: MOCK_INPUT_TOKENS,
        output_tokens: MOCK_OUTPUT_TOKENS,
        model_used: MOCK_MODEL,
      }, strings);
    }
    if (!isSuccessfulScenario(scenario)) throw scenarioError(scenario);

    return validateProviderResult('bulk', {
      results: strings.map((item) => ({
        id: item.id,
        translation: this.mark(item.content, targetLang),
        success: true,
      })),
      tokens_used: MOCK_TOKENS,
      input_tokens: MOCK_INPUT_TOKENS,
      output_tokens: MOCK_OUTPUT_TOKENS,
      model_used: MOCK_MODEL,
    }, strings);
  }

  async translateStructured(
    fields: StructuredTranslationFields,
    _sourceLang: string,
    targetLang: string,
    _tone?: Tone,
    context?: MockTranslationContext
  ): Promise<StructuredTranslationResponse> {
    const active = this.resolveContext(context);
    const scenario = this.validateContext(active);
    await this.beforeCall(active, scenario);

    if (scenario === 'malformed_response') {
      return validateProviderResult('structured', {
        translated_title: 42,
        tokens_used: MOCK_TOKENS,
        input_tokens: MOCK_INPUT_TOKENS,
        output_tokens: MOCK_OUTPUT_TOKENS,
        processing_time_ms: 0,
        model_used: MOCK_MODEL,
      }, fields);
    }
    if (!isSuccessfulScenario(scenario)) throw scenarioError(scenario);

    return validateProviderResult('structured', {
      ...(fields.title === undefined ? {} : { translated_title: this.mark(fields.title, targetLang) }),
      ...(fields.excerpt === undefined ? {} : { translated_excerpt: this.mark(fields.excerpt, targetLang) }),
      ...(fields.content === undefined ? {} : { translated_content: this.mark(fields.content, targetLang) }),
      tokens_used: MOCK_TOKENS,
      input_tokens: MOCK_INPUT_TOKENS,
      output_tokens: MOCK_OUTPUT_TOKENS,
      processing_time_ms: 0,
      model_used: MOCK_MODEL,
    }, fields);
  }

  private resolveContext(context?: MockTranslationContext): MockTranslationContext {
    return { ...this.context, ...context };
  }

  private validateContext(context: MockTranslationContext): MockTranslationScenario {
    const scenario = context.scenario ?? 'success';
    if (!MOCK_TRANSLATION_SCENARIOS.includes(scenario)) {
      throw new Error(`Unsupported mock translation scenario: ${String(scenario)}`);
    }
    if (scenario !== 'success') {
      if (!context.jobId || !context.attempt) {
        throw new Error('Mock async scenarios require persisted jobId and attempt');
      }
    }
    return scenario;
  }

  private async beforeCall(context: MockTranslationContext, scenario: MockTranslationScenario): Promise<void> {
    if (scenario === 'success' && !context.jobId) return;
    if (!context.jobId || !context.attempt) {
      throw new Error('Mock async scenarios require persisted jobId and attempt');
    }
    await this.store.recordCall(context.jobId, context.attempt);
    if (scenario === 'processing_hold' || scenario === 'pending_hold') {
      await this.store.waitForRelease(context.jobId, context.signal ?? context.abortSignal);
    }
  }

  private mark(content: string, targetLang: string): string {
    return `[${targetLang}] ${content}`;
  }

  private textResult(content: string, targetLang: string): GeminiTranslationResponse {
    return {
      translation: this.mark(content, targetLang),
      tokens_used: MOCK_TOKENS,
      input_tokens: MOCK_INPUT_TOKENS,
      output_tokens: MOCK_OUTPUT_TOKENS,
      processing_time_ms: 0,
      model_used: MOCK_MODEL,
    };
  }
}

function isSuccessfulScenario(scenario: MockTranslationScenario): boolean {
  return scenario === 'success' || scenario === 'pending_hold' || scenario === 'processing_hold';
}

function scenarioError(scenario: MockTranslationScenario): TranslationProviderError {
  switch (scenario) {
    case 'rate_limited':
      return new TranslationProviderError({ kind: 'rate_limited' });
    case 'transient_failure':
      return new TranslationProviderError({ kind: 'transient' });
    case 'permanent_failure':
      return new TranslationProviderError({ kind: 'permanent' });
    case 'timeout':
      return new TranslationProviderError({ kind: 'timeout' });
    default:
      return new TranslationProviderError({ kind: 'permanent' });
  }
}

export const mockTranslationProvider = new MockTranslationProvider();

export default mockTranslationProvider;
