const API_BASE = '/triviai/api';

export interface TriviaQuestion {
  question: string;
  options: string[];
  correctAnswer: string;
  hostCommentary: string;
  source?: string;
  fallbackReason?: string;
  model?: string;
  providerMessage?: string;
}

interface UserFacingErrorContext {
  requestType?: string;
  model?: string;
  detail?: string;
}

async function postJson<T>(path: string, payload: Record<string, unknown>): Promise<T> {
  const response = await fetch(`${API_BASE}${path}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  const data = await response.json().catch(() => ({}));
  if (!response.ok) {
    const message = typeof data?.error === 'string' ? data.error : `Request failed with ${response.status}`;
    throw new Error(message);
  }
  return data as T;
}

export function getUserFacingErrorMessage(error: unknown, context: UserFacingErrorContext = {}): string {
  const raw = error instanceof Error ? error.message : String(error ?? 'Unknown error');
  const normalized = raw.replace(/\s+/g, ' ').trim();
  const requestLabel = context.requestType ?? 'This request';
  const modelLabel = context.model ? ` (${context.model})` : '';
  const detailLabel = context.detail ? ` ${context.detail}` : '';

  if (
    /RESOURCE_EXHAUSTED|quota|rate limit|429|GenerateRequestsPerDayPerProjectPerModel-FreeTier/i.test(
      normalized
    )
  ) {
    return `${requestLabel}${modelLabel} hit Gemini free-tier quota.${detailLabel} Please wait a bit and try again.`;
  }

  if (/microphone|getUserMedia|NotFoundError|permission/i.test(normalized)) {
    return `${requestLabel} could not access the microphone. Please check browser permissions and try again.`;
  }

  if (/network|fetch|Failed to fetch|NetworkError/i.test(normalized)) {
    return `${requestLabel} could not reach Gemini right now. Please check the connection and try again.`;
  }

  return `${requestLabel} failed.${detailLabel} Please try again.`;
}

export interface SpeechResponse {
  audio: string;
  sampleRate: number;
  voice: string;
}

export async function generateTriviaQuestion(topic: string, personality: string): Promise<TriviaQuestion> {
  const response = await postJson<TriviaQuestion>('/question', {
    topic,
    personality,
    excludeQuestions: [],
  });

  if (response.source === 'fallback') {
    throw new Error(
      response.fallbackReason ||
        'Gemini could not generate a topic-grounded question right now.',
    );
  }

  return response;
}

export async function generateTriviaQuestionWithHistory(
  topic: string,
  personality: string,
  excludeQuestions: string[],
): Promise<TriviaQuestion> {
  const response = await postJson<TriviaQuestion>('/question', {
    topic,
    personality,
    excludeQuestions,
  });

  if (response.source === 'fallback') {
    throw new Error(
      response.fallbackReason ||
        'Gemini could not generate a topic-grounded question right now.',
    );
  }

  return response;
}

export async function evaluateAnswer(question: string, correctAnswer: string, userAnswer: string, personality: string): Promise<string> {
  const response = await postJson<{ feedback: string }>('/answer', {
    question,
    correctAnswer,
    userAnswer,
    personality,
  });
  return response.feedback || 'I have no words.';
}

export async function generateSpeech(text: string): Promise<SpeechResponse> {
  return postJson<SpeechResponse>('/speak', { text });
}

function chooseVariant(variants: string[], previousFeedback?: string): string {
  const normalizedPrevious = previousFeedback?.trim();
  const filtered = normalizedPrevious
    ? variants.filter((variant) => variant.trim() !== normalizedPrevious)
    : variants;
  const pool = filtered.length > 0 ? filtered : variants;
  return pool[Math.floor(Math.random() * pool.length)];
}

export function buildInstantFeedback(
  correctAnswer: string,
  userAnswer: string,
  personality: string,
  previousFeedback?: string,
): string {
  const isCorrect = userAnswer.trim().toLowerCase() === correctAnswer.trim().toLowerCase();
  const personalityKey = personality.trim().toLowerCase();

  if (isCorrect) {
    if (personalityKey.includes('sarcastic')) {
      return chooseVariant(
        [
          'Wow. You actually nailed it.',
          'Correct. I was prepared to be disappointed.',
          'Right answer. Miracles do happen.',
        ],
        previousFeedback,
      );
    }
    if (personalityKey.includes('pirate')) {
      return chooseVariant(
        [
          'Aye, that be the right answer.',
          'Dead on. Ye picked the right one.',
          'A clean hit, matey. Correct answer.',
        ],
        previousFeedback,
      );
    }
    if (personalityKey.includes('posh')) {
      return chooseVariant(
        [
          'Correct. A suitably polished answer.',
          'Quite right. Nicely done.',
          'Correct answer. Very well judged.',
        ],
        previousFeedback,
      );
    }
    if (personalityKey.includes('hype')) {
      return chooseVariant(
        [
          'Correct answer. Big energy. Huge hit.',
          'That is right. Crowd goes wild.',
          'Correct. Clean score on the board.',
        ],
        previousFeedback,
      );
    }
    return chooseVariant(
      [
        'Correct answer. Clean hit.',
        'That is right. Nice read.',
        'Correct. Strong answer.',
      ],
      previousFeedback,
    );
  }

  if (personalityKey.includes('sarcastic')) {
    return chooseVariant(
      [
        `Nope. The right answer was ${correctAnswer}.`,
        `Not this time. The right answer was ${correctAnswer}.`,
        `Swing and a miss. The correct answer was ${correctAnswer}.`,
      ],
      previousFeedback,
    );
  }
  if (personalityKey.includes('pirate')) {
    return chooseVariant(
      [
        `Not quite. The right answer was ${correctAnswer}, matey.`,
        `Close, but no treasure. The correct answer was ${correctAnswer}.`,
        `Wrong turn at sea. The right answer was ${correctAnswer}.`,
      ],
      previousFeedback,
    );
  }
  if (personalityKey.includes('posh')) {
    return chooseVariant(
      [
        `Not quite. The correct answer was ${correctAnswer}.`,
        `A near miss. The right answer was ${correctAnswer}.`,
        `Incorrect, I’m afraid. The correct answer was ${correctAnswer}.`,
      ],
      previousFeedback,
    );
  }
  if (personalityKey.includes('hype')) {
    return chooseVariant(
      [
        `Missed it. The right answer was ${correctAnswer}.`,
        `Not this round. The correct answer was ${correctAnswer}.`,
        `Close, but the board wanted ${correctAnswer}.`,
      ],
      previousFeedback,
    );
  }
  return chooseVariant(
    [
      `Not quite. The right answer was ${correctAnswer}.`,
      `Close, but the correct answer was ${correctAnswer}.`,
      `That one missed. The right answer was ${correctAnswer}.`,
    ],
    previousFeedback,
  );
}
