'use client';

// Auth client for the CapCut Web backend (Express on VPS).
// Handles register/login/logout/me + project/asset API calls.

const API_BASE =
  process.env.NEXT_PUBLIC_API_URL ||
  (typeof window !== 'undefined' && window.location.hostname !== 'localhost'
    ? `${window.location.protocol}//${window.location.hostname}:3019`
    : 'http://localhost:3019');

const TOKEN_KEY = 'capcut-auth-token';

export interface User {
  id: string;
  username: string;
  displayName: string;
  createdAt: number;
}

export interface ServerProjectSummary {
  id: string;
  name: string;
  clipsCount: number;
  updatedAt: number;
}

export interface ServerAssetMeta {
  id: string;
  size: number;
}

class CapcutAuthError extends Error {
  constructor(message: string, public status?: number) {
    super(message);
    this.name = 'CapcutAuthError';
  }
}

function getToken(): string | null {
  if (typeof window === 'undefined') return null;
  return localStorage.getItem(TOKEN_KEY);
}

function setToken(token: string | null): void {
  if (typeof window === 'undefined') return;
  if (token) localStorage.setItem(TOKEN_KEY, token);
  else localStorage.removeItem(TOKEN_KEY);
}

async function request<T>(
  path: string,
  opts: {
    method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
    body?: unknown;
    isFormData?: boolean;
    auth?: boolean;
  } = {},
): Promise<T> {
  const { method = 'GET', body, isFormData, auth = true } = opts;
  const headers: Record<string, string> = {};
  if (!isFormData && body) headers['Content-Type'] = 'application/json';
  if (auth) {
    const t = getToken();
    if (t) headers['Authorization'] = `Bearer ${t}`;
  }
  let payload: BodyInit | undefined;
  if (body) {
    payload = isFormData ? (body as FormData) : JSON.stringify(body);
  }
  const res = await fetch(`${API_BASE}${path}`, {
    method,
    headers,
    body: payload,
  });
  const text = await res.text();
  let data: unknown;
  try {
    data = text ? JSON.parse(text) : {};
  } catch {
    data = { error: text };
  }
  if (!res.ok) {
    const msg =
      (data as { error?: string })?.error || `HTTP ${res.status}: ${res.statusText}`;
    throw new CapcutAuthError(msg, res.status);
  }
  return data as T;
}

// ----- Auth -----

export async function register(
  username: string,
  password: string,
): Promise<{ token: string; user: User }> {
  const res = await request<{ token: string; user: User }>(
    '/api/auth/register',
    { method: 'POST', body: { username, password }, auth: false },
  );
  setToken(res.token);
  return res;
}

export async function login(
  username: string,
  password: string,
): Promise<{ token: string; user: User }> {
  const res = await request<{ token: string; user: User }>(
    '/api/auth/login',
    { method: 'POST', body: { username, password }, auth: false },
  );
  setToken(res.token);
  return res;
}

export async function logout(): Promise<void> {
  try {
    await request('/api/auth/logout', { method: 'POST' });
  } catch {
    // ignore — logout should never fail
  }
  setToken(null);
}

export async function me(): Promise<User | null> {
  try {
    const res = await request<{ user: User }>('/api/auth/me');
    return res.user;
  } catch {
    setToken(null);
    return null;
  }
}

export function getApiBase(): string {
  return API_BASE;
}

export function isLoggedIn(): boolean {
  return !!getToken();
}

export { CapcutAuthError, getToken };

// ----- Projects -----

export async function listServerProjects(): Promise<ServerProjectSummary[]> {
  const res = await request<{ projects: ServerProjectSummary[] }>('/api/projects');
  return res.projects;
}

export async function createServerProject(
  name: string,
  project: unknown,
): Promise<ServerProjectSummary> {
  const res = await request<{ project: ServerProjectSummary }>('/api/projects', {
    method: 'POST',
    body: { name, project },
  });
  return res.project;
}

export async function getServerProject(
  id: string,
): Promise<{ project: unknown; assetsMeta: ServerAssetMeta[] } | null> {
  try {
    return await request<{ project: unknown; assetsMeta: ServerAssetMeta[] }>(
      `/api/projects/${id}`,
    );
  } catch {
    return null;
  }
}

export async function updateServerProject(
  id: string,
  project: unknown,
): Promise<void> {
  await request(`/api/projects/${id}`, { method: 'PUT', body: { project } });
}

export async function deleteServerProject(id: string): Promise<void> {
  await request(`/api/projects/${id}`, { method: 'DELETE' });
}

// ----- Assets -----

export async function uploadServerAsset(
  projectId: string,
  assetId: string,
  file: Blob,
): Promise<{ size: number }> {
  const fd = new FormData();
  fd.append('file', file, assetId);
  const res = await request<{ ok: boolean; size: number }>(
    `/api/projects/${projectId}/assets/${assetId}`,
    { method: 'PUT', body: fd, isFormData: true },
  );
  return { size: res.size };
}

export async function downloadServerAsset(
  projectId: string,
  assetId: string,
): Promise<Blob | null> {
  const t = getToken();
  const res = await fetch(
    `${API_BASE}/api/projects/${projectId}/assets/${assetId}`,
    { headers: t ? { Authorization: `Bearer ${t}` } : {} },
  );
  if (!res.ok) return null;
  return await res.blob();
}

export async function deleteServerAsset(
  projectId: string,
  assetId: string,
): Promise<void> {
  await request(`/api/projects/${projectId}/assets/${assetId}`, {
    method: 'DELETE',
  });
}
