import { buildApiUrl } from '@/constants/Api';
import AsyncStorage from '@react-native-async-storage/async-storage';

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';

let inMemoryToken: string | null = null;

export async function setAuthToken(token: string | null): Promise<void> {
  inMemoryToken = token;
}

export function getAuthToken(): string | null {
  return inMemoryToken;
}

export type ApiRequestOptions = {
  method?: HttpMethod;
  headers?: Record<string, string>;
  body?: any;
  signal?: AbortSignal;
};

export type ApiResponse<T> = {
  data: T;
};

async function doFetch<T>(path: string, options: ApiRequestOptions = {}): Promise<T> {
  const url = buildApiUrl(path);
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(options.headers || {}),
  };

  const token = getAuthToken();
  if (token) {
    headers['Authorization'] = `Bearer ${token}`;
  }

  const response = await fetch(url, {
    method: options.method ?? 'GET',
    headers,
    body: options.body != null ? JSON.stringify(options.body) : undefined,
    signal: options.signal,
  });

  const text = await response.text();
  let json: any = null;
  try {
    json = text ? JSON.parse(text) : null;
  } catch {
    // 非 JSON 响应
  }

  if (!response.ok) {
    const errorMessage = (json && (json.message || json.error)) || `HTTP ${response.status}`;
    const error = new Error(errorMessage);
    // @ts-expect-error augment
    error.status = response.status;
    throw error;
  }

  // 支持后端返回 { data: ... } 或直接返回对象
  return (json && (json.data ?? json)) as T;
}

export const api = {
  get: <T>(path: string, options?: ApiRequestOptions) => doFetch<T>(path, { ...options, method: 'GET' }),
  post: <T>(path: string, body?: any, options?: ApiRequestOptions) => doFetch<T>(path, { ...options, method: 'POST', body }),
  put: <T>(path: string, body?: any, options?: ApiRequestOptions) => doFetch<T>(path, { ...options, method: 'PUT', body }),
  patch: <T>(path: string, body?: any, options?: ApiRequestOptions) => doFetch<T>(path, { ...options, method: 'PATCH', body }),
  delete: <T>(path: string, options?: ApiRequestOptions) => doFetch<T>(path, { ...options, method: 'DELETE' }),
};

export const STORAGE_KEYS = {
  authToken: '@auth_token',
  userProfile: '@user_profile',
  privacyAgreed: '@privacy_agreed',
} as const;

export async function loadPersistedToken(): Promise<string | null> {
  try {
    const t = await AsyncStorage.getItem(STORAGE_KEYS.authToken);
    return t || null;
  } catch {
    return null;
  }
}

// 流式文本 POST（基于 XMLHttpRequest），支持增量 onChunk 回调与取消
export type TextStreamCallbacks = {
  onChunk: (chunkText: string) => void;
  onEnd?: (conversationId?: string) => void;
  onError?: (error: any) => void;
};

export type TextStreamOptions = {
  headers?: Record<string, string>;
  timeoutMs?: number;
  signal?: AbortSignal;
};

export function postTextStream(path: string, body: any, callbacks: TextStreamCallbacks, options: TextStreamOptions = {}) {
  const url = buildApiUrl(path);
  const token = getAuthToken();
  const requestHeaders: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(options.headers || {}),
  };
  if (token) {
    requestHeaders['Authorization'] = `Bearer ${token}`;
  }

  const xhr = new XMLHttpRequest();
  let lastReadIndex = 0;
  let resolved = false;
  let conversationIdFromHeader: string | undefined = undefined;

  const abort = () => {
    try { xhr.abort(); } catch { }
  };

  const cleanup = () => {
    resolved = true;
  };

  // 日志：请求开始
  try {
    console.log('[AI_CHAT][stream] start', { url, hasToken: !!token, body });
  } catch { }

  xhr.open('POST', url, true);
  // 设置超时（可选）
  if (typeof options.timeoutMs === 'number') {
    xhr.timeout = options.timeoutMs;
  }
  // 设置请求头
  Object.entries(requestHeaders).forEach(([k, v]) => {
    try { xhr.setRequestHeader(k, v); } catch { }
  });

  // 进度事件：读取新增的响应文本
  xhr.onprogress = () => {
    try {
      const text = xhr.responseText ?? '';
      if (text.length > lastReadIndex) {
        const nextChunk = text.substring(lastReadIndex);
        lastReadIndex = text.length;
        // 首次拿到响应头时尝试解析会话ID
        if (!conversationIdFromHeader) {
          try {
            const rawHeaders = xhr.getAllResponseHeaders?.() || '';
            const matched = /^(.*)$/m.test(rawHeaders) ? rawHeaders : rawHeaders; // 保底，避免 TS 报错
            const headerLines = String(matched).split('\n');
            for (const line of headerLines) {
              const [hk, ...rest] = line.split(':');
              if (hk && hk.toLowerCase() === 'x-conversation-id') {
                conversationIdFromHeader = rest.join(':').trim();
                break;
              }
            }
          } catch { }
        }
        try {
          callbacks.onChunk(nextChunk);
        } catch (err) {
          console.warn('[AI_CHAT][stream] onChunk error', err);
        }
        try {
          console.log('[AI_CHAT][stream] chunk', { length: nextChunk.length, preview: nextChunk.slice(0, 50) });
        } catch { }
      }
    } catch (err) {
      console.warn('[AI_CHAT][stream] onprogress error', err);
    }
  };

  xhr.onreadystatechange = () => {
    if (xhr.readyState === xhr.DONE) {
      try { console.log('[AI_CHAT][stream] done', { status: xhr.status }); } catch { }
      if (!resolved) {
        cleanup();
        if (xhr.status >= 200 && xhr.status < 300) {
          try { callbacks.onEnd?.(conversationIdFromHeader); } catch { }
        } else {
          const error = new Error(`HTTP ${xhr.status}`);
          try { callbacks.onError?.(error); } catch { }
        }
      }
    }
  };

  xhr.onerror = (e) => {
    try { console.warn('[AI_CHAT][stream] xhr error', e); } catch { }
    if (!resolved) {
      cleanup();
      try { callbacks.onError?.(e); } catch { }
    }
  };

  xhr.ontimeout = () => {
    const err = new Error('Request timeout');
    try { console.warn('[AI_CHAT][stream] timeout'); } catch { }
    if (!resolved) {
      cleanup();
      try { callbacks.onError?.(err); } catch { }
    }
  };

  // AbortSignal 支持
  if (options.signal) {
    const onAbort = () => {
      try { console.log('[AI_CHAT][stream] aborted'); } catch { }
      abort();
    };
    if (options.signal.aborted) onAbort();
    else options.signal.addEventListener('abort', onAbort, { once: true });
  }

  try {
    const payload = body != null ? JSON.stringify(body) : undefined;
    xhr.send(payload);
  } catch (err) {
    try { console.warn('[AI_CHAT][stream] send error', err); } catch { }
    if (!resolved) {
      cleanup();
      try { callbacks.onError?.(err); } catch { }
    }
  }

  return { abort };
}


