import type {
  AuthUser,
  HistoryPoint,
  VehicleAlertSummary,
  VehicleColorKey,
  VehicleKind,
  VehicleSummary,
} from "@tracker/shared";

const API_BASE_URL = "/api";

export type SessionPayload = {
  token: string;
  user: AuthUser;
};

export type AdminUserSummary = {
  id: string;
  email: string;
  firstName: string;
  lastName: string;
  role: "admin" | "user";
  createdAt: string;
  vehicleIds: string[];
};

export type AdminDeviceSummary = {
  id: string;
  imei: string;
  protocol_name: string;
  phone_number: string | null;
  status: string;
  last_seen: string | null;
  vehicle_id: string | null;
};

export type CompanySettingsSummary = {
  addressInput: string;
  addressLabel: string;
  lat: number;
  lon: number;
  updatedAt: string;
} | null;

export type CompanyRouteSummary = {
  distanceKm: number;
  durationMinutes: number;
  companyAddress: string;
};

export const sessionStorageKey = "tracker.session";

export const loadSession = (): SessionPayload | null => {
  if (typeof window === "undefined") {
    return null;
  }

  const raw = window.localStorage.getItem(sessionStorageKey);
  if (!raw) {
    return null;
  }

  try {
    return JSON.parse(raw) as SessionPayload;
  } catch {
    return null;
  }
};

export const saveSession = (session: SessionPayload) => {
  window.localStorage.setItem(sessionStorageKey, JSON.stringify(session));
};

export const clearSession = () => {
  window.localStorage.removeItem(sessionStorageKey);
};

export const apiFetch = async <T>(path: string, token?: string, init?: RequestInit): Promise<T> => {
  const response = await fetch(`${API_BASE_URL}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...(init?.headers ?? {}),
    },
    cache: "no-store",
  });

  if (!response.ok) {
    const body = await response.json().catch(() => ({ message: "Request failed" }));
    throw new Error(body.message ?? "Request failed");
  }

  if (response.status === 204) {
    return undefined as T;
  }

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

export const loginRequest = (email: string, password: string) =>
  apiFetch<{ token: string; user: AuthUser }>("/auth/login", undefined, {
    method: "POST",
    body: JSON.stringify({ email, password }),
  });

export const fetchVehicles = (token: string) =>
  apiFetch<{ items: VehicleSummary[] }>("/vehicles", token);

export const fetchVehicleHistory = (token: string, vehicleId: string, from: string, to: string) =>
  apiFetch<{
    items: Array<{
      id: number;
      lat: number;
      lon: number;
      speed?: number | null;
      heading?: number | null;
      deviceTime?: string | null;
      serverTime?: string | null;
      ignition?: boolean | null;
      battery?: number | null;
      gsmSignal?: number | null;
      satelliteCount?: number | null;
      gpsValid?: boolean | null;
      charging?: boolean | null;
      defense?: boolean | null;
      positionType?: string | null;
      device_time?: string | null;
      server_time?: string | null;
      gsm_signal?: number | null;
      satellite_count?: number | null;
      gps_valid?: boolean | null;
      position_type?: string | null;
    }>;
  }>(
    `/vehicles/${vehicleId}/history?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}&limit=5000`,
    token,
  ).then((response) => ({
    items: response.items.map((item) => ({
      id: item.id,
      lat: item.lat,
      lon: item.lon,
      speed: item.speed ?? null,
      heading: item.heading ?? null,
      deviceTime: item.deviceTime ?? item.device_time ?? null,
      serverTime: item.serverTime ?? item.server_time ?? "",
      ignition: item.ignition ?? null,
      battery: item.battery ?? null,
      gsmSignal: item.gsmSignal ?? item.gsm_signal ?? null,
      satelliteCount: item.satelliteCount ?? item.satellite_count ?? null,
      gpsValid: item.gpsValid ?? item.gps_valid ?? null,
      charging: item.charging ?? null,
      defense: item.defense ?? null,
      positionType: item.positionType ?? item.position_type ?? null,
    })),
  }));

export const reverseGeocode = (token: string, lat: number, lon: number) =>
  apiFetch<{ item: { label: string } }>(
    `/geocoding/reverse?lat=${encodeURIComponent(String(lat))}&lon=${encodeURIComponent(String(lon))}`,
    token,
  );

export const fetchUnassignedDevices = (token: string) =>
  apiFetch<{
    items: Array<{
      imei: string;
      protocol_name: string;
      first_seen: string;
      last_seen: string;
      raw_payload: string;
    }>;
  }>("/devices/unassigned", token);

export const fetchUsers = (token: string) =>
  apiFetch<{ items: AdminUserSummary[] }>("/users", token);

export const fetchDevices = (token: string) =>
  apiFetch<{ items: AdminDeviceSummary[] }>("/devices", token);

export const fetchCompanySettings = (token: string) =>
  apiFetch<{ item: CompanySettingsSummary }>("/settings/company", token);

export const updateCompanySettings = (token: string, payload: { address: string }) =>
  apiFetch<{ item: CompanySettingsSummary }>("/settings/company", token, {
    method: "PATCH",
    body: JSON.stringify(payload),
  });

export const fetchCompanyRoute = (token: string, lat: number, lon: number) =>
  apiFetch<{ item: CompanyRouteSummary }>(
    `/settings/company-route?lat=${encodeURIComponent(String(lat))}&lon=${encodeURIComponent(String(lon))}`,
    token,
  );

export const createUser = (
  token: string,
  payload: { email: string; firstName: string; lastName: string; password: string; role: "admin" | "user"; vehicleIds: string[] },
) =>
  apiFetch<{ item: AdminUserSummary }>("/users", token, {
    method: "POST",
    body: JSON.stringify(payload),
  });

export const updateUser = (
  token: string,
  userId: string,
  payload: { firstName: string; lastName: string; password?: string; role: "admin" | "user"; vehicleIds: string[] },
) =>
  apiFetch<{ item: AdminUserSummary }>(`/users/${userId}`, token, {
    method: "PATCH",
    body: JSON.stringify(payload),
  });

export const deleteUser = (token: string, userId: string) =>
  apiFetch<unknown>(`/users/${userId}`, token, {
    method: "DELETE",
  });

export const fetchActiveAlerts = (token: string) =>
  apiFetch<{ items: VehicleAlertSummary[] }>("/alerts/active", token);

export const fetchRecentAlerts = (token: string) =>
  apiFetch<{ items: VehicleAlertSummary[] }>("/alerts/recent", token);

export const acknowledgeAlert = (token: string, alertId: string) =>
  apiFetch<{ item: { id: string; acknowledgedAt: string } }>(`/alerts/${alertId}/acknowledge`, token, {
    method: "PATCH",
  });

export const createVehicle = (
  token: string,
  payload: { name: string; plateNumber?: string; colorKey: VehicleColorKey; vehicleKind: VehicleKind },
) =>
  apiFetch<{ item: { id: string; name: string; plateNumber: string | null; colorKey: VehicleColorKey; vehicleKind: VehicleKind } }>("/vehicles", token, {
    method: "POST",
    body: JSON.stringify({
      name: payload.name,
      plateNumber: payload.plateNumber,
      colorKey: payload.colorKey,
      vehicleKind: payload.vehicleKind,
      userIds: [],
    }),
  });

export const createDevice = (
  token: string,
  payload: { imei: string; phoneNumber?: string; vehicleId?: string },
) =>
  apiFetch<{ item: { id: string; imei: string; vehicle_id: string | null } }>("/devices", token, {
    method: "POST",
    body: JSON.stringify({
      imei: payload.imei,
      phoneNumber: payload.phoneNumber,
      protocolName: "gt06",
      vehicleId: payload.vehicleId,
    }),
  });

export const updateVehicle = (
  token: string,
  vehicleId: string,
  payload: { name: string; plateNumber?: string | null; colorKey: VehicleColorKey; vehicleKind: VehicleKind },
) =>
  apiFetch<{ item: { id: string; name: string; plateNumber: string | null; colorKey: VehicleColorKey; vehicleKind: VehicleKind } }>(
    `/vehicles/${vehicleId}`,
    token,
    {
      method: "PATCH",
      body: JSON.stringify({
        name: payload.name,
        plateNumber: payload.plateNumber ?? null,
        colorKey: payload.colorKey,
        vehicleKind: payload.vehicleKind,
      }),
    },
  );

export const deleteVehicle = (token: string, vehicleId: string) =>
  apiFetch<unknown>(`/vehicles/${vehicleId}`, token, {
    method: "DELETE",
  });

export const updateDevice = (
  token: string,
  deviceId: string,
  payload: { imei: string; phoneNumber?: string | null; vehicleId?: string | null },
) =>
  apiFetch<{ item: { id: string; imei: string; phone_number: string | null; vehicle_id: string | null } }>(
    `/devices/${deviceId}`,
    token,
    {
      method: "PATCH",
      body: JSON.stringify({
        imei: payload.imei,
        phoneNumber: payload.phoneNumber ?? null,
        protocolName: "gt06",
        vehicleId: payload.vehicleId ?? null,
      }),
    },
  );

export const deleteDevice = (token: string, deviceId: string) =>
  apiFetch<unknown>(`/devices/${deviceId}`, token, {
    method: "DELETE",
  });
