const API_BASE = "";

const TOKEN_KEY = "dtp_auth_token";
const USER_KEY = "dtp_user";

let isRefreshing = false;
let refreshPromise: Promise<string> | null = null;

export interface ApiResponse<T = unknown> {
  success: boolean;
  message?: string;
  user?: T;
  token?: string;
  data?: T;
}

function getToken(): string | null {
  try {
    return localStorage.getItem(TOKEN_KEY);
  } catch {
    return null;
  }
}

function setToken(token: string): void {
  localStorage.setItem(TOKEN_KEY, token);
}

function getUser(): User | null {
  try {
    const userData = localStorage.getItem(USER_KEY);
    return userData ? JSON.parse(userData) : null;
  } catch {
    return null;
  }
}

function setUser(user: User | null): void {
  if (user) {
    localStorage.setItem(USER_KEY, JSON.stringify(user));
  } else {
    localStorage.removeItem(USER_KEY);
  }
}

function signOut(): void {
  localStorage.removeItem(TOKEN_KEY);
  localStorage.removeItem(USER_KEY);
  window.location.href = "/";
}

async function refreshAuthToken(): Promise<string> {
  const response = await fetch(`${API_BASE}/api/v1/auth/renew-token`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    credentials: "include",
  });

  if (!response.ok) {
    throw new Error(`Token refresh failed: ${response.status}`);
  }

  const text = await response.text();
  try {
    const json = JSON.parse(text) as ApiResponse<{ token: string }>;
    if (!json.success || !json.data?.token) {
      throw new Error(json.message || "Token refresh failed");
    }
    return json.data.token;
  } catch {
    throw new Error(`Invalid refresh response: ${text.slice(0, 200)}`);
  }
}

async function request<T>(
  method: string,
  path: string,
  body?: Record<string, unknown>,
  retryCount = 0,
): Promise<T> {
  const token = getToken();
  const headers: Record<string, string> = {
    "Content-Type": "application/json",
  };

  if (token) {
    headers["Authorization"] = `Bearer ${token}`;
  }

  const options: RequestInit = {
    method,
    headers,
    credentials: "include",
  };

  if (body) {
    options.body = JSON.stringify(body);
  }

  const response = await fetch(`${API_BASE}${path}`, options);

  if (response.status === 401 && retryCount === 0) {
    try {
      if (!isRefreshing) {
        isRefreshing = true;
        refreshPromise = refreshAuthToken();
      }
      
      const newToken = await refreshPromise;
      setToken(newToken);
      isRefreshing = false;
      refreshPromise = null;
      
      return request<T>(method, path, body, retryCount + 1);
    } catch {
      isRefreshing = false;
      refreshPromise = null;
      signOut();
      throw new Error("Session expired. Please sign in again.");
    }
  }

  const text = await response.text();

  if (!text) {
    throw new Error("Empty response");
  }

  try {
    var json = JSON.parse(text) as ApiResponse<T>;
  } catch {
    throw new Error(`Invalid JSON: ${text.slice(0, 200)}`);
  }

  if (!json.success) {
    throw new Error(json.message || "Request failed");
  }

  if (json.token !== undefined && json.user !== undefined) {
    return json as T;
  }
  if (json.data !== undefined) {
    return json.data as T;
  }
  return json as T;
}

export const api = {
  get: <T>(path: string) => request<T>("GET", path),
  post: <T>(path: string, body?: Record<string, unknown>) =>
    request<T>("POST", path, body),
  put: <T>(path: string, body: Record<string, unknown>) =>
    request<T>("PUT", path, body),
  delete: <T>(path: string) => request<T>("DELETE", path),
};

export interface User {
  _id: string;
  email: string;
  displayName: string;
  flags: string[];
  persona?: string;
}

export interface AuthResponse {
  user: User;
  token: string;
}

export interface Project {
  _id: string;
  createdAt: string;
  user: string;
  status: "active" | "inactive" | "archived";
  name: string;
  slug: string;
  gitUrl?: string;
}

export const userApi = {
  updateSettings: (data: {
    displayName?: string;
    currentPassword?: string;
    password?: string;
    persona?: string;
  }) => api.put<User>("/api/v1/user/settings", data),
};

export const projectApi = {
  getAll: () => api.get<Project[]>("/api/v1/projects"),
  get: (id: string) => api.get<Project>(`/api/v1/projects/${id}`),
  create: (data: { name: string; slug: string; gitUrl?: string }) =>
    api.post<Project>("/api/v1/projects", data),
  update: (
    id: string,
    data: Partial<{
      name: string;
      slug: string;
      gitUrl: string;
      status: string;
    }>,
  ) => api.put<Project>(`/api/v1/projects/${id}`, data),
  delete: (id: string) => api.delete<void>(`/api/v1/projects/${id}`),
};

export interface DroneRegistration {
  _id: string;
  hostname: string;
  workspaceDir: string;
  status: "starting" | "available" | "busy" | "offline";
  user: string;
  createdAt: string;
  updatedAt: string;
}

export const droneApi = {
  getAll: () => api.get<DroneRegistration[]>("/api/v1/drone/registration"),
  getForManager: () =>
    api.get<DroneRegistration[]>("/api/v1/drone/registration/manager"),
  terminate: (registrationId: string) =>
    api.post<ApiResponse>(
      `/api/v1/drone/registration/${registrationId}/terminate`,
    ),
};

export interface AiModelCapabilities {
  canCallTools: boolean;
  hasVision: boolean;
  hasEmbedding: boolean;
  hasThinking: boolean;
  isInstructTuned: boolean;
}

export interface AiModelSettings {
  temperature?: number;
  topP?: number;
  topK?: number;
  numCtx?: number;
}

export interface AiModel {
  id: string;
  name: string;
  parameterCount?: number;
  parameterLabel?: string;
  contextWindow?: number;
  capabilities: AiModelCapabilities;
  settings?: AiModelSettings;
}

export interface AiProvider {
  _id: string;
  name: string;
  apiType: "ollama" | "openai";
  baseUrl: string;
  enabled: boolean;
  models: AiModel[];
  lastModelRefresh: string;
}

export const providerApi = {
  getAll: () => api.get<AiProvider[]>("/api/v1/providers"),
  get: (id: string) => api.get<AiProvider>(`/api/v1/providers/${id}`),
};

export enum ChatSessionMode {
  Plan = "plan",
  Build = "build",
  Test = "test",
  Ship = "ship",
  Develop = "dev",
}

export interface ChatSessionStats {
  turnCount: number;
  toolCallCount: number;
  inputTokens: number;
  outputTokens: number;
}

export interface ChatSession {
  _id: string;
  createdAt: string;
  lastMessageAt?: string;
  user: string | any;
  project: string | any;
  name: string;
  mode: ChatSessionMode;
  provider: string | AiProvider;
  selectedModel: string;
  reasoningEffort?: string;
  stats: ChatSessionStats;
  pins: Array<{ _id?: string; content: string }>;
}

export interface ChatTurnStats {
  toolCallCount: number;
  inputTokens: number;
  thinkingTokenCount: number;
  responseTokens: number;
  durationMs: number;
  durationLabel: string;
}

export interface ChatTurnPrompts {
  user: string;
  system?: string;
}

export interface ChatTurnBlockThinking {
  mode: 'thinking';
  createdAt: string;
  content: string;
}

export interface ChatTurnBlockResponding {
  mode: 'responding';
  createdAt: string;
  content: string;
}

export interface ChatTurnBlockTool {
  mode: 'tool';
  createdAt: string;
  content: {
    callId: string;
    name: string;
    parameters?: string;
    response?: string;
  };
}

export type ChatTurnBlock = ChatTurnBlockThinking | ChatTurnBlockResponding | ChatTurnBlockTool;

export interface ChatTurn {
  _id: string;
  createdAt: string;
  user: string | any;
  project: string | any;
  session: string | ChatSession;
  provider: string | AiProvider;
  llm: string;
  mode: ChatSessionMode;
  status: "processing" | "finished" | "error";
  prompts: ChatTurnPrompts;
  blocks: ChatTurnBlock[];
  errorMessage?: string;
  toolCalls: Array<{
    callId: string;
    name: string;
    parameters?: string;
    response?: string;
  }>;
  subagents: any[];
  stats: ChatTurnStats;
}

export const chatSessionApi = {
  getAll: (projectId?: string) =>
    api.get<ChatSession[]>(
      `/api/v1/chat-sessions${projectId ? `?projectId=${projectId}` : ""}`,
    ),
  get: (id: string) => api.get<ChatSession>(`/api/v1/chat-sessions/${id}`),
  create: (data: {
    projectId: string;
    providerId: string;
    selectedModel: string;
    mode?: ChatSessionMode;
    name?: string;
  }) => api.post<ChatSession>("/api/v1/chat-sessions", data),
  update: (id: string, data: Partial<ChatSession>) =>
    api.put<ChatSession>(`/api/v1/chat-sessions/${id}`, data),
  delete: (id: string) => api.delete<void>(`/api/v1/chat-sessions/${id}`),
  getTurns: (id: string) =>
    api.get<ChatTurn[]>(`/api/v1/chat-sessions/${id}/turns`),
};
