import type {
  ModelListResponse,
  StreamAnalyzeRequest,
  Step1Result,
  Step0Result,
  CategoryDefinition,
  DynamicStep1Result,
  DAGStreamAnalyzeResponse,
  TransformationRequest,
  TransformationCategoryResult,
  ExpertTransformationRequest,
  ExpertTransformationCategoryResult,
  ExpertProfile,
  DeduplicationRequest,
  DeduplicationResult,
  PatentSearchRequest,
  PatentSearchResponse,
  BatchPatentSearchRequest,
  BatchPatentSearchResponse,
} from '../types';

// 自動使用當前瀏覽器的 hostname，支援遠端存取
const API_BASE_URL = `http://${window.location.hostname}:8001/api`;

export interface SSECallbacks {
  onStep0Start?: () => void;
  onStep0Complete?: (result: Step0Result) => void;
  onCategoriesResolved?: (categories: CategoryDefinition[]) => void;
  onStep1Start?: () => void;
  onStep1Complete?: (result: Step1Result | DynamicStep1Result) => void;
  onRelationshipsStart?: () => void;
  onRelationshipsComplete?: (count: number) => void;
  onDone?: (response: DAGStreamAnalyzeResponse) => void;
  onError?: (error: string) => void;
}

export async function analyzeAttributesStream(
  request: StreamAnalyzeRequest,
  callbacks: SSECallbacks
): Promise<void> {
  const response = await fetch(`${API_BASE_URL}/analyze`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.statusText}`);
  }

  const reader = response.body?.getReader();
  if (!reader) {
    throw new Error('No response body');
  }

  const decoder = new TextDecoder();
  let buffer = '';

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

    buffer += decoder.decode(value, { stream: true });

    // 解析 SSE 事件
    const lines = buffer.split('\n\n');
    buffer = lines.pop() || ''; // 保留未完成的部分

    for (const chunk of lines) {
      if (!chunk.trim()) continue;

      const eventMatch = chunk.match(/event: (\w+)/);
      const dataMatch = chunk.match(/data: (.+)/s);

      if (eventMatch && dataMatch) {
        const eventType = eventMatch[1];
        try {
          const eventData = JSON.parse(dataMatch[1]);

          switch (eventType) {
            case 'step0_start':
              callbacks.onStep0Start?.();
              break;
            case 'step0_complete':
              callbacks.onStep0Complete?.(eventData.result);
              break;
            case 'categories_resolved':
              callbacks.onCategoriesResolved?.(eventData.categories);
              break;
            case 'step1_start':
              callbacks.onStep1Start?.();
              break;
            case 'step1_complete':
              callbacks.onStep1Complete?.(eventData.result);
              break;
            case 'relationships_start':
              callbacks.onRelationshipsStart?.();
              break;
            case 'relationships_complete':
              callbacks.onRelationshipsComplete?.(eventData.count);
              break;
            case 'done':
              callbacks.onDone?.(eventData);
              break;
            case 'error':
              callbacks.onError?.(eventData.error);
              break;
          }
        } catch (e) {
          console.error('Failed to parse SSE event:', e, chunk);
        }
      }
    }
  }
}

export async function getModels(): Promise<ModelListResponse> {
  const response = await fetch(`${API_BASE_URL}/models`);

  if (!response.ok) {
    throw new Error(`API error: ${response.statusText}`);
  }

  return response.json();
}

// ===== Transformation Agent API =====

export interface TransformationSSECallbacks {
  onKeywordStart?: () => void;
  onKeywordComplete?: (keywords: string[]) => void;
  onDescriptionStart?: () => void;
  onDescriptionComplete?: (count: number) => void;
  onDone?: (result: TransformationCategoryResult) => void;
  onError?: (error: string) => void;
}

export async function transformCategoryStream(
  request: TransformationRequest,
  callbacks: TransformationSSECallbacks
): Promise<void> {
  const response = await fetch(`${API_BASE_URL}/transformation/category`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.statusText}`);
  }

  const reader = response.body?.getReader();
  if (!reader) {
    throw new Error('No response body');
  }

  const decoder = new TextDecoder();
  let buffer = '';

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

    buffer += decoder.decode(value, { stream: true });

    // 解析 SSE 事件
    const lines = buffer.split('\n\n');
    buffer = lines.pop() || '';

    for (const chunk of lines) {
      if (!chunk.trim()) continue;

      const eventMatch = chunk.match(/event: (\w+)/);
      const dataMatch = chunk.match(/data: (.+)/s);

      if (eventMatch && dataMatch) {
        const eventType = eventMatch[1];
        try {
          const eventData = JSON.parse(dataMatch[1]);

          switch (eventType) {
            case 'keyword_start':
              callbacks.onKeywordStart?.();
              break;
            case 'keyword_complete':
              callbacks.onKeywordComplete?.(eventData.keywords);
              break;
            case 'description_start':
              callbacks.onDescriptionStart?.();
              break;
            case 'description_complete':
              callbacks.onDescriptionComplete?.(eventData.count);
              break;
            case 'done':
              callbacks.onDone?.(eventData.result);
              break;
            case 'error':
              callbacks.onError?.(eventData.error);
              break;
          }
        } catch (e) {
          console.error('Failed to parse SSE event:', e, chunk);
        }
      }
    }
  }
}

// ===== Expert Transformation Agent API =====

export interface ExpertTransformationSSECallbacks {
  onExpertStart?: () => void;
  onExpertComplete?: (experts: ExpertProfile[]) => void;
  onKeywordStart?: () => void;
  onKeywordProgress?: (data: { attribute: string; count: number }) => void;
  onKeywordComplete?: (totalKeywords: number) => void;
  onDescriptionStart?: () => void;
  onDescriptionComplete?: (count: number) => void;
  onDone?: (data: { result: ExpertTransformationCategoryResult; experts: ExpertProfile[] }) => void;
  onError?: (error: string) => void;
}

export async function expertTransformCategoryStream(
  request: ExpertTransformationRequest,
  callbacks: ExpertTransformationSSECallbacks
): Promise<void> {
  const response = await fetch(`${API_BASE_URL}/expert-transformation/category`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    throw new Error(`API error: ${response.statusText}`);
  }

  const reader = response.body?.getReader();
  if (!reader) {
    throw new Error('No response body');
  }

  const decoder = new TextDecoder();
  let buffer = '';

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

    buffer += decoder.decode(value, { stream: true });

    // 解析 SSE 事件
    const lines = buffer.split('\n\n');
    buffer = lines.pop() || '';

    for (const chunk of lines) {
      if (!chunk.trim()) continue;

      const eventMatch = chunk.match(/event: (\w+)/);
      const dataMatch = chunk.match(/data: (.+)/s);

      if (eventMatch && dataMatch) {
        const eventType = eventMatch[1];
        try {
          const eventData = JSON.parse(dataMatch[1]);

          switch (eventType) {
            case 'expert_start':
              callbacks.onExpertStart?.();
              break;
            case 'expert_complete':
              callbacks.onExpertComplete?.(eventData.experts);
              break;
            case 'keyword_start':
              callbacks.onKeywordStart?.();
              break;
            case 'keyword_progress':
              callbacks.onKeywordProgress?.(eventData);
              break;
            case 'keyword_complete':
              callbacks.onKeywordComplete?.(eventData.total_keywords);
              break;
            case 'description_start':
              callbacks.onDescriptionStart?.();
              break;
            case 'description_complete':
              callbacks.onDescriptionComplete?.(eventData.count);
              break;
            case 'done':
              callbacks.onDone?.(eventData);
              break;
            case 'error':
              callbacks.onError?.(eventData.error);
              break;
          }
        } catch (e) {
          console.error('Failed to parse SSE event:', e, chunk);
        }
      }
    }
  }
}

// ===== Deduplication Agent API =====

export async function deduplicateDescriptions(
  request: DeduplicationRequest
): Promise<DeduplicationResult> {
  const response = await fetch(`${API_BASE_URL}/deduplication/deduplicate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`API error: ${response.status} - ${errorText}`);
  }

  return response.json();
}

// ===== Patent Search API =====

export async function searchPatents(
  request: PatentSearchRequest
): Promise<PatentSearchResponse> {
  const response = await fetch(`${API_BASE_URL}/patent/search`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`API error: ${response.status} - ${errorText}`);
  }

  return response.json();
}

export async function batchSearchPatents(
  request: BatchPatentSearchRequest
): Promise<BatchPatentSearchResponse> {
  const response = await fetch(`${API_BASE_URL}/patent/search/batch`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(request),
  });

  if (!response.ok) {
    const errorText = await response.text();
    throw new Error(`API error: ${response.status} - ${errorText}`);
  }

  return response.json();
}
