import AsyncStorage from '@react-native-async-storage/async-storage';

export const DEFAULT_API_BASE_URL = process.env.EXPO_PUBLIC_API_URL ?? 'http://localhost:3000/api';

const TOKEN_KEY = 'auth:token';
const USER_KEY = 'auth:user';
export const API_URL_KEY = 'settings:apiUrl';

function normalizeApiUrl(url: string): string {
  return url.trim().replace(/\/+$/, '');
}

export async function getApiBaseUrl(): Promise<string> {
  try {
    const stored = await AsyncStorage.getItem(API_URL_KEY);
    if (!stored) return DEFAULT_API_BASE_URL;
    try {
      const parsed = JSON.parse(stored) as unknown;
      if (typeof parsed === 'string' && parsed.trim()) {
        return normalizeApiUrl(parsed);
      }
    } catch {
      // fall through to raw value
    }
    if (stored.trim()) {
      return normalizeApiUrl(stored);
    }
  } catch {
    // ignore
  }
  return DEFAULT_API_BASE_URL;
}

export async function setApiBaseUrl(url: string): Promise<void> {
  const normalized = normalizeApiUrl(url);
  try {
    if (normalized) {
      await AsyncStorage.setItem(API_URL_KEY, normalized);
    } else {
      await AsyncStorage.removeItem(API_URL_KEY);
    }
  } catch {
    // ignore
  }
}

export interface AuthUser {
  id: string;
  username: string;
}

export async function getAuthToken(): Promise<string | null> {
  try {
    return await AsyncStorage.getItem(TOKEN_KEY);
  } catch {
    return null;
  }
}

export async function getAuthUser(): Promise<AuthUser | null> {
  try {
    const raw = await AsyncStorage.getItem(USER_KEY);
    return raw ? (JSON.parse(raw) as AuthUser) : null;
  } catch {
    return null;
  }
}

export async function setAuth(token: string, user: AuthUser): Promise<void> {
  try {
    await AsyncStorage.setItem(TOKEN_KEY, token);
    await AsyncStorage.setItem(USER_KEY, JSON.stringify(user));
  } catch {
    // ignore
  }
}

export async function signOutAuth(): Promise<void> {
  try {
    await AsyncStorage.removeItem(TOKEN_KEY);
    await AsyncStorage.removeItem(USER_KEY);
  } catch {
    // ignore
  }
}

export async function apiFetch(path: string, options: RequestInit = {}): Promise<Response> {
  const token = await getAuthToken();
  const apiBaseUrl = await getApiBaseUrl();
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(options.headers as Record<string, string> | undefined),
  };
  if (token) {
    headers.Authorization = `Bearer ${token}`;
  }
  const response = await fetch(`${apiBaseUrl}${path}`, { ...options, headers });
  if (!response.ok) {
    let message = `Request failed (${response.status})`;
    let details: any = null;
    try {
      const body = await response.json();
      if (body && typeof body.message === 'string') {
        message = body.message;
      }
      if (body && body.error && body.error.details) {
        details = body.error.details;
      }
    } catch {
      // ignore
    }
    const error = new Error(message);
    (error as any).details = details;
    (error as any).status = response.status;
    throw error;
  }
  return response;
}

export async function login(username: string, password: string): Promise<AuthUser> {
  const response = await apiFetch('/auth/login', {
    method: 'POST',
    body: JSON.stringify({ username, password }),
  });
  const data = await response.json();
  await setAuth(data.token, data.user);
  return data.user as AuthUser;
}

export async function register(username: string, password: string): Promise<AuthUser> {
  const response = await apiFetch('/auth/register', {
    method: 'POST',
    body: JSON.stringify({ username, password }),
  });
  const data = await response.json();
  await setAuth(data.token, data.user);
  return data.user as AuthUser;
}
