import type { ActiveSession, AuthTokens, PublicUser } from '@/lib/api';

const DEFAULT_API_URL = 'http://localhost:3000';

export const MOBILE_AUTH_TOKEN_KEY = 'lendry_mobile_access_token';
export const MOBILE_REFRESH_TOKEN_KEY = 'lendry_mobile_refresh_token';
export const MOBILE_SESSION_ID_KEY = 'lendry_mobile_session_id';
export const MOBILE_USER_KEY = 'lendry_mobile_user';
export const MOBILE_API_URL_KEY = 'lendry_mobile_api_url';

export class MobileApiError extends Error {
  constructor(
    message: string,
    readonly status: number,
    readonly code?: string
  ) {
    super(message);
    this.name = 'MobileApiError';
  }
}

export function getMobileApiUrl() {
  return (window.localStorage.getItem(MOBILE_API_URL_KEY) ?? import.meta.env.VITE_API_URL ?? DEFAULT_API_URL).replace(/\/$/, '');
}

export function setMobileApiUrl(url: string) {
  window.localStorage.setItem(MOBILE_API_URL_KEY, url.replace(/\/$/, ''));
}

export function readStoredMobileAuth() {
  const token = window.localStorage.getItem(MOBILE_AUTH_TOKEN_KEY);
  const refreshToken = window.localStorage.getItem(MOBILE_REFRESH_TOKEN_KEY);
  const sessionId = window.localStorage.getItem(MOBILE_SESSION_ID_KEY);
  const rawUser = window.localStorage.getItem(MOBILE_USER_KEY);
  let user: PublicUser | null = null;
  if (rawUser) {
    try {
      user = JSON.parse(rawUser) as PublicUser;
    } catch {
      user = null;
    }
  }
  return { token, refreshToken, sessionId, user };
}

export function persistMobileAuth(auth: AuthTokens) {
  window.localStorage.setItem(MOBILE_AUTH_TOKEN_KEY, auth.accessToken);
  window.localStorage.setItem(MOBILE_REFRESH_TOKEN_KEY, auth.refreshToken);
  window.localStorage.setItem(MOBILE_SESSION_ID_KEY, auth.sessionId);
  window.localStorage.setItem(MOBILE_USER_KEY, JSON.stringify(auth.user));
}

export function clearMobileAuth() {
  window.localStorage.removeItem(MOBILE_AUTH_TOKEN_KEY);
  window.localStorage.removeItem(MOBILE_REFRESH_TOKEN_KEY);
  window.localStorage.removeItem(MOBILE_SESSION_ID_KEY);
  window.localStorage.removeItem(MOBILE_USER_KEY);
}

async function parseError(response: Response) {
  try {
    const body = (await response.json()) as { message?: string | string[]; error?: string; code?: string };
    const message = Array.isArray(body.message) ? body.message.join('\n') : body.message ?? body.error ?? 'Ошибка запроса';
    return new MobileApiError(message, response.status, body.code);
  } catch {
    return new MobileApiError('Ошибка запроса', response.status);
  }
}

export async function mobileFetch<T>(path: string, options: RequestInit = {}, token?: string | null): Promise<T> {
  const response = await fetch(`${getMobileApiUrl()}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...options.headers
    }
  });

  if (!response.ok) {
    throw await parseError(response);
  }

  return response.json() as Promise<T>;
}

export interface TotpChallengeResponse {
  totpChallengeToken: string;
}

export type PasswordLoginResponse = AuthTokens | {
  requiresTotp: true;
  totpChallengeToken: string;
};

export async function loginWithPassword(login: string, password: string) {
  return mobileFetch<PasswordLoginResponse>('/auth/login/password', {
    method: 'POST',
    body: JSON.stringify({
      login,
      password,
      fingerprint: crypto.randomUUID(),
      deviceName: 'Lendry ID Mobile',
      deviceType: 'MOBILE'
    })
  });
}

export async function beginTotpLogin(recipient: string) {
  return mobileFetch<TotpChallengeResponse>('/auth/totp/begin', {
    method: 'POST',
    body: JSON.stringify({
      recipient,
      fingerprint: crypto.randomUUID(),
      deviceName: 'Lendry ID Mobile',
      deviceType: 'MOBILE'
    })
  });
}

export async function verifyTotpLogin(totpChallengeToken: string, code: string) {
  return mobileFetch<AuthTokens>('/auth/totp/verify', {
    method: 'POST',
    body: JSON.stringify({ totpChallengeToken, code })
  });
}

export async function approveQrLogin(sessionId: string, token: string) {
  return mobileFetch(`/auth/advanced/qr/session/${encodeURIComponent(sessionId)}/approve`, { method: 'POST' }, token);
}

export async function fetchActiveSessions(userId: string, token: string) {
  return mobileFetch<{ sessions?: ActiveSession[] }>(`/security/users/${encodeURIComponent(userId)}/sessions`, {}, token);
}

export async function revokeSession(userId: string, sessionId: string, token: string) {
  return mobileFetch(`/security/users/${encodeURIComponent(userId)}/sessions/${encodeURIComponent(sessionId)}/revoke`, { method: 'POST' }, token);
}
