import type { MediaType, Recommendation, RecommendationSummary, FeedbackEntry } from '../types/index.js';

const BASE = '/api';

async function request<T>(path: string, options?: RequestInit): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    headers: {
      ...(options?.body ? { 'Content-Type': 'application/json' } : {}),
    },
    ...options,
  });
  if (!res.ok) {
    const text = await res.text();
    throw new Error(`HTTP ${res.status}: ${text}`);
  }
  return res.json() as Promise<T>;
}

export function createRecommendation(body: {
  main_prompt: string;
  liked_series: string;
  disliked_series: string;
  themes: string;
  brainstorm_count?: number;
  media_type: MediaType;
  use_web_search?: boolean;
  use_validator?: boolean;
  hard_requirements?: boolean;
  self_expansive?: boolean;
  expansive_passes?: number;
  expansive_mode?: 'soft' | 'extreme';
}): Promise<{ id: string }> {
  return request('/recommendations', {
    method: 'POST',
    body: JSON.stringify(body),
  });
}

export function listRecommendations(): Promise<RecommendationSummary[]> {
  return request('/recommendations');
}

export function getRecommendation(id: string): Promise<Recommendation> {
  return request(`/recommendations/${id}`);
}

export function rerankRecommendation(id: string): Promise<{ ok: boolean }> {
  return request(`/recommendations/${id}/rerank`, { method: 'POST' });
}

export function submitFeedback(body: {
  item_name: string;
  stars: number;
  feedback?: string;
}): Promise<{ ok: boolean }> {
  return request('/feedback', {
    method: 'POST',
    body: JSON.stringify(body),
  });
}

export function getFeedback(): Promise<FeedbackEntry[]> {
  return request('/feedback');
}

export function deleteRecommendation(id: string): Promise<{ ok: boolean }> {
  return request(`/recommendations/${id}`, { method: 'DELETE' });
}

export function createContinuousRecommendation(body: {
  liked_series: string;
  disliked_series?: string;
  themes?: string;
  requirements?: string;
  avoid?: string;
  total_count: number;
  media_type: MediaType;
  use_web_search?: boolean;
  validate_results?: boolean;
}): Promise<{ id: string }> {
  return (async () => {
    const res = await fetch(`${BASE}/recommendations/continuous`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'text/event-stream',
      },
      body: JSON.stringify(body),
    });

    if (!res.ok) {
      const text = await res.text();
      throw new Error(`HTTP ${res.status}: ${text}`);
    }

    if (!res.body) {
      throw new Error('Missing response stream for continuous recommendation');
    }

    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    try {
      while (true) {
        const { value, done } = await reader.read();

        if (value) {
          buffer += decoder.decode(value, { stream: !done });
        }

        let boundary = buffer.indexOf('\n\n');
        while (boundary !== -1) {
          const rawEvent = buffer.slice(0, boundary).trim();
          buffer = buffer.slice(boundary + 2);

          if (rawEvent) {
            const dataLine = rawEvent
              .split('\n')
              .find((line) => line.startsWith('data:'));

            if (dataLine) {
              const payload = dataLine.slice(5).trim();
              const event = JSON.parse(payload) as { type?: string; id?: string };

              if (event.type === 'created' && event.id) {
                await reader.cancel();
                return { id: event.id };
              }
            }
          }

          boundary = buffer.indexOf('\n\n');
        }

        if (done) {
          break;
        }
      }
    } finally {
      reader.releaseLock();
    }

    throw new Error('Continuous recommendation stream ended before returning an id');
  })();
}
