export type ApiSession = { baseUrl: string; token: string }

export type Project = {
  id: string
  name: string
  identifier: string
  icon: string
  background: string
  description: string
}

export type WorkspaceTask = {
  id: string
  projectId: string
  title: string
  summary: string
  completed: boolean
  owner: string
  due: string | null
  createdAt: string
  completedAt: string | null
  tagId: string | null
  tag: string
}

export type NoteSource = {
  id: string
  projectId: string
  kind: string
  title: string
  updatedAt: string
  tag: string
  source: string
}

export type CronPlan = {
  id: string
  projectId: string
  title: string
  schedule: string
  nextRun: string | null
  enabled: boolean
  lastResult: string
  owner: string
}

export type Workspace = {
  project: Project & { initials: string; unreadCount: number }
  tags: Array<{ id: string; name: string }>
  tasks: WorkspaceTask[]
  notesSources: NoteSource[]
  aiSessions: Array<{ id: string; projectId: string; title: string; summary: string; updatedAt: string; references: string[] }>
  cronPlans: CronPlan[]
}

export type Expert = {
  id: string
  slug: string
  category: string
  categoryName: string
  name: string
  description: string
  emoji: string
  color: string
}

export type AISession = {
  id: string
  projectId: string
  title: string
  context: string
  status: string
  expert: Expert | null
  createdAt: string
  updatedAt: string
}

export class ApiError extends Error {
  constructor(public status: number, public code: string, message: string) {
    super(message)
    this.name = 'ApiError'
  }
}

let baseUrl = normalizeBaseUrl(import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:9150')

export function configureApi(value: string) {
  baseUrl = normalizeBaseUrl(value)
}

export async function login(server: string, email: string, password: string): Promise<ApiSession> {
  configureApi(server)
  const response = await request<{ token: string }>('/api/v1/auth/login', { method: 'POST', body: { email, password } })
  return { baseUrl, token: response.token }
}

export async function checkServerConnection(server: string, signal?: AbortSignal) {
  try {
    const response = await fetch(`${normalizeBaseUrl(server)}/api/v1/status`, { signal })
    if (!response.ok) return false
    const payload = await response.json() as { timestamp?: unknown }
    return typeof payload.timestamp === 'string'
  } catch (error) {
    if (error instanceof DOMException && error.name === 'AbortError') throw error
    return false
  }
}

export async function fetchProjects(session: ApiSession) {
  useSessionBase(session)
  return request<Project[]>('/api/v1/projects', { token: session.token })
}

export async function fetchWorkspace(session: ApiSession, projectId: string) {
  useSessionBase(session)
  return request<Workspace>(`/api/v1/projects/${projectId}/workspace`, { token: session.token })
}

export async function createProject(session: ApiSession, name: string) {
  useSessionBase(session)
  const identifier = `${slugify(name) || 'project'}-${Date.now().toString(36)}`
  return request<Project>('/api/v1/projects', {
    method: 'POST', token: session.token,
    body: { name, identifier, icon: 'folder', background: '#165DFF', description: '' },
  })
}

export async function createTask(session: ApiSession, projectId: string, title: string, tag?: string) {
  useSessionBase(session)
  return request(`/api/v1/projects/${projectId}/tasks`, {
    method: 'POST', token: session.token, body: { title, description: '', status: 'open', tag },
  })
}

export async function updateTask(session: ApiSession, projectId: string, task: WorkspaceTask) {
  useSessionBase(session)
  return request(`/api/v1/projects/${projectId}/tasks/${task.id}`, {
    method: 'PATCH', token: session.token,
    body: { title: task.title, description: task.summary, completed: !task.completed, tag: task.tag },
  })
}

export async function uploadSource(session: ApiSession, projectId: string, file: File) {
  useSessionBase(session)
  const body = new FormData()
  body.append('file', file)
  body.append('title', file.name)
  return request(`/api/v1/projects/${projectId}/sources`, { method: 'POST', token: session.token, body })
}

export async function createCron(session: ApiSession, projectId: string, title: string, schedule: string) {
  useSessionBase(session)
  return request(`/api/v1/projects/${projectId}/cron-plans`, {
    method: 'POST', token: session.token, body: { title, schedule, enabled: true },
  })
}

export async function fetchExperts(session: ApiSession) {
  useSessionBase(session)
  return request<Expert[]>('/api/v1/ai-experts', { token: session.token })
}

export async function fetchAISessions(session: ApiSession, projectId: string) {
  useSessionBase(session)
  return request<AISession[]>(`/api/v1/projects/${projectId}/ai-sessions`, { token: session.token })
}

export async function createAISession(session: ApiSession, projectId: string, expertId: string, context: string) {
  useSessionBase(session)
  return request<AISession>(`/api/v1/projects/${projectId}/ai-sessions`, {
    method: 'POST', token: session.token,
    body: { title: Array.from(context).slice(0, 36).join(''), context, expertId },
  })
}

type RequestOptions = { method?: string; token?: string; body?: unknown; signal?: AbortSignal }

async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
  const isForm = options.body instanceof FormData
  let response: Response
  try {
    response = await fetch(`${baseUrl}${path}`, {
      method: options.method ?? 'GET',
      headers: {
        ...(!isForm && options.body !== undefined ? { 'Content-Type': 'application/json' } : {}),
        ...(options.token ? { Authorization: `Bearer ${options.token}` } : {}),
      },
      body: options.body === undefined ? undefined : isForm ? options.body as FormData : JSON.stringify(options.body),
      signal: options.signal,
    })
  } catch {
    throw new ApiError(0, 'network_error', '无法连接服务器，请检查地址和网络')
  }
  if (!response.ok) {
    const payload = await response.json().catch(() => null) as { error?: { code?: string; message?: string } } | null
    throw new ApiError(response.status, payload?.error?.code ?? 'request_failed', payload?.error?.message ?? '请求失败，请稍后重试')
  }
  if (response.status === 204) return undefined as T
  return response.json() as Promise<T>
}

function useSessionBase(session: ApiSession) {
  baseUrl = normalizeBaseUrl(session.baseUrl)
}

function normalizeBaseUrl(value: string) {
  const normalized = value.trim().replace(/\/+$/, '')
  if (!normalized || /^https?:\/\//i.test(normalized)) return normalized
  return `http://${normalized}`
}

function slugify(value: string) {
  return value.toLowerCase().trim().replace(/[^a-z0-9\u4e00-\u9fa5]+/g, '-').replace(/^-|-$/g, '')
}
