import { API_BASE_URL } from '@/src/config';

type TokenGetter = () => string | null;

type RequestOptions = RequestInit & {
  skipAuth?: boolean;
};

const normalizePath = (path: string): string => {
  if (path.startsWith('http://') || path.startsWith('https://')) return path;
  return `${API_BASE_URL}${path.startsWith('/') ? path : `/${path}`}`;
};

export const createApi = (getDeviceToken: TokenGetter) => {
  const request = async <T = any>(path: string, options: RequestOptions = {}): Promise<T> => {
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      ...(options.headers as Record<string, string> | undefined),
    };

    if (!options.skipAuth) {
      const token = getDeviceToken();
      if (token) {
        headers.Authorization = `Bearer ${token}`;
      }
    }

    const response = await fetch(normalizePath(path), {
      ...options,
      headers,
      credentials: 'include',
    });

    const data = await response.json().catch(() => ({}));

    if (!response.ok) {
      const message =
        (data as { message?: string; error?: string }).message ||
        (data as { message?: string; error?: string }).error ||
        response.statusText ||
        'Request failed';
      throw new Error(message);
    }

    return data as T;
  };

  return {
    request,
    auth: {
      signUp: (data: { email: string; password: string; name: string }) =>
        request('/api/auth/sign-up/email', { method: 'POST', body: JSON.stringify(data), skipAuth: true }),
      signIn: (data: { email: string; password: string }) =>
        request('/api/auth/sign-in/email', { method: 'POST', body: JSON.stringify(data), skipAuth: true }),
      getSession: () => request('/api/auth/get-session', { skipAuth: true }),
      signOut: () => request('/api/auth/sign-out', { method: 'POST', body: JSON.stringify({}), skipAuth: true }),
    },
    devices: {
      register: (data: Record<string, unknown>) =>
        request<{ device: any; deviceToken: string }>('/devices/register', {
          method: 'POST',
          body: JSON.stringify(data),
        }),
      list: () => request<{ devices: any[] }>('/devices'),
      update: (deviceId: string, data: Record<string, unknown>) =>
        request(`/devices/${deviceId}`, { method: 'PATCH', body: JSON.stringify(data) }),
      listLinks: () => request<{ links: any[] }>('/device-links'),
      link: (cameraDeviceId: string, clientDeviceId: string) =>
        request('/device-links', {
          method: 'POST',
          body: JSON.stringify({ cameraDeviceId, clientDeviceId }),
        }),
      unlink: (linkId: string) => request(`/device-links/${linkId}`, { method: 'DELETE' }),
    },
    streams: {
      request: (cameraDeviceId: string) =>
        request('/streams/request', {
          method: 'POST',
          body: JSON.stringify({ cameraDeviceId, reason: 'on_demand' }),
        }),
      accept: (id: string) => request(`/streams/${id}/accept`, { method: 'POST', body: JSON.stringify({}) }),
      end: (id: string) =>
        request(`/streams/${id}/end`, { method: 'POST', body: JSON.stringify({ reason: 'completed' }) }),
      getPublishCreds: (id: string) => request(`/streams/${id}/publish-credentials`),
      getSubscribeCreds: (id: string) => request(`/streams/${id}/subscribe-credentials`),
    },
    events: {
      startMotion: () =>
        request<{ event: { id: string } }>('/events/motion/start', {
          method: 'POST',
          body: JSON.stringify({ title: 'Simulated Motion', triggeredBy: 'motion' }),
        }),
      endMotion: (id: string) =>
        request(`/events/${id}/motion/end`, { method: 'POST', body: JSON.stringify({ status: 'completed' }) }),
      finalizeRecording: (id: string, payload: Record<string, unknown>) =>
        request(`/recordings/${id}/finalize`, { method: 'POST', body: JSON.stringify(payload) }),
    },
    ops: {
      listRecordings: () => request<{ recordings: any[] }>('/recordings/me/list'),
      getRecordingDownloadUrl: (recordingId: string) => request<{ downloadUrl: string }>(`/recordings/${recordingId}/download-url`),
      listNotifications: () => request('/push-notifications/me'),
    },
  };
};

export type ApiClient = ReturnType<typeof createApi>;
