import type { TenantContext } from "@platform-types";

import { getStoredSessionToken } from "./session";

const DEFAULT_HEADERS = {
  "Content-Type": "application/json"
};

export interface BackendHealthResponse {
  status: string;
  service: string;
}

export interface BackendCatalogResponse {
  items: Array<{
    key: string;
    name: string;
    status: string;
  }>;
}

export interface AuthStatusResponse {
  status: string;
  mode: string;
  tenant_count: number;
  user_count: number;
  first_run: boolean;
  super_admin_bootstrap_required?: boolean;
  super_admin_identifier?: string;
  next_step: string;
}

export interface AssistantProfileResponse {
  assistant_name: string;
  assistant_surface: string;
  assistant_summary: string;
  tenant_slug: string;
  venue_names: string[];
  enabled_modules: string[];
}

export interface AssistantConversationMessage {
  role: "user" | "assistant";
  content: string;
}

export interface AssistantChatRequest {
  message: string;
  thread_id?: string | null;
  conversation: AssistantConversationMessage[];
}

export interface AssistantChatResponse {
  assistant_name: string;
  reply: string;
  model: string;
  assistant_surface: "home" | "documents" | "menu";
  thread_id: string | null;
  updated_at: string | null;
}

export interface AssistantThreadResponse {
  assistant_name: string;
  assistant_surface: "home" | "documents" | "menu";
  thread_id: string | null;
  updated_at: string | null;
  messages: AssistantConversationMessage[];
}

export interface MenuPromptSettings {
  tenant_name: string;
  tenant_slug: string;
  venue_name: string;
  base_prompt: string;
  prompt_preview: string;
  assistant_description: string;
  sales_focus: string;
  menu_text: string;
  cocktail_list_text: string;
  updated_at: string | null;
}

export interface MenuPromptSettingsPayload {
  sales_focus: string;
  menu_text: string;
  cocktail_list_text: string;
}

export interface GoogleWorkspaceStatusResponse {
  configured: boolean;
  connected: boolean;
  ready: boolean;
  account_email: string | null;
  expires_at: string | null;
  redirect_uri: string | null;
  scopes: string[];
  granted_scopes: string[];
  missing_scopes: string[];
  next_step: string;
}

export interface GoogleWorkspaceAuthorizationResponse {
  authorization_url: string;
}

export interface GoogleWorkspacePreviewRequest {
  kind: "doc" | "sheet";
  title: string;
  prompt: string;
  destination_folder_id?: string;
}

export interface GoogleWorkspaceDocumentPreview {
  kind: "doc" | "sheet";
  title: string;
  summary: string;
  destination_folder_id: string | null;
  content: string | null;
  columns: string[];
  rows: string[][];
}

export interface GoogleWorkspaceCreateRequest {
  kind: "doc" | "sheet";
  title: string;
  destination_folder_id?: string;
  content?: string;
  columns?: string[];
  rows?: string[][];
}

export interface GoogleWorkspaceCreateResponse {
  kind: "doc" | "sheet";
  file_id: string;
  title: string;
  web_url: string;
  destination_folder_id: string | null;
  account_email: string | null;
}

export interface AuthPayload {
  identifier: string;
  password: string;
}

export interface AuthenticatedUser {
  id: string;
  tenant_id: string;
  name?: string | null;
  username?: string | null;
  email: string;
  role: string;
  permissions: string[];
}

export interface PlatformAdminContext {
  is_super_admin: boolean;
  is_impersonating: boolean;
  home_tenant_id: string;
  home_tenant_slug: string;
  home_tenant_name: string;
  acting_tenant_id: string;
  acting_tenant_slug: string;
}

export interface TenantStaffUser {
  id: string;
  tenant_id: string;
  name?: string | null;
  username?: string | null;
  email: string;
  phone_number?: string | null;
  role: string;
  permissions: string[];
  created_at: string;
}

export interface TenantStaffUserRequest {
  name: string;
  username: string;
  email: string;
  phone_number?: string;
  password?: string;
  permissions: string[];
}

export interface UpdatePasswordRequest {
  current_password?: string;
  new_password: string;
}

export interface TimeclockEntry {
  id: string;
  user_id: string;
  user_name?: string | null;
  username?: string | null;
  user_email?: string | null;
  started_at: string;
  ended_at?: string | null;
  duration_seconds: number;
  duration_hours: number;
  is_active: boolean;
  started_source: string;
  ended_source?: string | null;
  notes?: string | null;
  entry_date?: string | null;
  created_at: string;
  updated_at: string;
}

export interface TimeclockUserSummary {
  user_id: string;
  user_name?: string | null;
  username?: string | null;
  user_email?: string | null;
  entries: number;
  total_seconds: number;
  total_hours: number;
  active_entries: number;
  last_started_at?: string | null;
}

export interface TimeclockStatusResponse {
  can_manage_team: boolean;
  active_entry?: TimeclockEntry | null;
  today_seconds: number;
  today_hours: number;
  week_seconds: number;
  week_hours: number;
  recent_entries: TimeclockEntry[];
}

export interface TimeclockOverviewResponse {
  can_manage_team: boolean;
  filters: {
    user_id?: string | null;
    start_date?: string | null;
    end_date?: string | null;
    limit: number;
  };
  entries: TimeclockEntry[];
  summary_by_user: TimeclockUserSummary[];
  active_entries: TimeclockEntry[];
}

export interface InventoryWarehouse {
  id: string;
  name: string;
  product_count: number;
  total_equivalent_units: number;
  theoretical_total_equivalent_units?: number;
  real_total_equivalent_units?: number;
  latest_inventory_date?: string | null;
  latest_inventory?: InventorySession | null;
  inventory_session_count?: number;
  incoming_since_latest_inventory_equivalent_units?: number;
  created_at: string;
  updated_at: string;
}

export interface InventoryWarehouseListResponse {
  warehouses: InventoryWarehouse[];
  warehouse_count: number;
  total_products: number;
  total_equivalent_units: number;
  theoretical_total_equivalent_units?: number;
  real_total_equivalent_units?: number;
  inventory_session_count?: number;
}

export interface InventoryWarehouseDetailLot {
  id: string;
  lot_code: string;
  quantity: number;
  units_per_pack?: number | null;
  equivalent_units: number;
  created_at: string;
  updated_at: string;
}

export interface InventoryWarehouseDetailItem {
  id: string;
  product_id?: number | null;
  product_name: string;
  supplier_name: string;
  total_equivalent_units: number;
  lot_count: number;
  lots: InventoryWarehouseDetailLot[];
  created_at: string;
  updated_at: string;
}

export interface InventoryWarehouseDetailResponse {
  warehouse: InventoryWarehouse;
  items: InventoryWarehouseDetailItem[];
  current_items?: InventoryWarehouseDetailItem[];
  real_items?: InventoryWarehouseDetailItem[];
  comparison_items?: Array<{
    product_name: string;
    supplier_name: string;
    theoretical_units: number;
    real_units: number;
    delta_units: number;
  }>;
  latest_inventory?: InventorySession | null;
  total_products: number;
  total_equivalent_units: number;
  theoretical_total_equivalent_units?: number;
  real_total_equivalent_units?: number;
  incoming_since_latest_inventory_equivalent_units?: number;
}

export interface InventorySession {
  id: string;
  warehouse_id: string;
  warehouse_name: string;
  inventory_date: string;
  label: string;
  created_by_name: string;
  total_products: number;
  total_equivalent_units: number;
  created_at: string;
  updated_at: string;
}

export interface InventorySessionListResponse {
  warehouse: InventoryWarehouse;
  sessions: InventorySession[];
  total_count: number;
}

export interface InventorySessionDetailResponse {
  warehouse: InventoryWarehouse;
  session: InventorySession;
  items: InventoryWarehouseDetailItem[];
  total_products: number;
  total_equivalent_units: number;
}

export interface InventorySnapshot {
  id: string;
  snapshot_date: string;
  label: string;
  created_by_name: string;
  total_warehouses: number;
  total_products: number;
  total_equivalent_units: number;
  created_at: string;
  updated_at: string;
}

export interface InventorySnapshotListResponse {
  snapshots: InventorySnapshot[];
  total_count: number;
}

export interface InventoryConsumptionItem {
  product_name: string;
  supplier_name: string;
  opening_units: number;
  incoming_units: number;
  closing_units: number;
  consumed_units: number;
}

export interface InventoryConsumptionResponse {
  warehouse?: InventoryWarehouse;
  sessions?: InventorySession[];
  start_session?: InventorySession | null;
  end_session?: InventorySession | null;
  snapshots?: InventorySnapshot[];
  start_snapshot?: InventorySnapshot | null;
  end_snapshot?: InventorySnapshot | null;
  period_days: number;
  total_opening_units: number;
  total_incoming_units: number;
  total_closing_units: number;
  total_consumed_units: number;
  incoming_data_gaps?: Array<{
    product_name: string;
    supplier_name: string;
    lot_code: string;
  }>;
  items: InventoryConsumptionItem[];
  calculation_mode: string;
}

export interface InventoryProductOption {
  id: number;
  product_name: string;
  lot_code: string;
  supplier_name: string;
  product_code?: string | null;
  units_per_pack?: number | null;
  final_price_vat?: number | null;
  requires_units_per_pack: boolean;
}

export interface InventoryProductSearchResponse {
  catalog_available: boolean;
  items: InventoryProductOption[];
}

export interface RegisterTenantRequest {
  locale_name: string;
  address: string;
  phone_number?: string;
  whatsapp_number?: string;
  admin_name: string;
  username: string;
  email: string;
  password: string;
}

export interface BootstrapSuperAdminRequest {
  password: string;
}

export interface UpdateSuperAdminPasswordRequest {
  current_password: string;
  new_password: string;
}

export interface AdminTenantSummary {
  tenant: TenantContext["tenant"];
  venue: TenantContext["venues"][number] | null;
  admin_user: TenantContext["users"][number] | null;
  enabled_modules: number;
  total_modules: number;
}

export interface AdminSuperUserSummary {
  id: string;
  name?: string | null;
  username?: string | null;
  email: string;
  role: string;
  created_at: string;
  password_configured: boolean;
}

export interface AdminOverviewResponse {
  super_admin: AdminSuperUserSummary;
  tenants: AdminTenantSummary[];
}

export interface AdminTenantRequest {
  locale_name: string;
  address: string;
  phone_number?: string;
  whatsapp_number?: string;
  admin_name: string;
  username: string;
  email: string;
  password?: string;
}

export interface AuthResponse {
  success: boolean;
  session_token: string;
  current_user: AuthenticatedUser;
  tenant_context: TenantContext;
  platform_admin?: PlatformAdminContext | null;
  detail?: string;
}

export interface FiscalDocumentRead {
  id: string;
  original_name: string;
  display_name: string;
  mime_type: string;
  kind: string;
  file_size_bytes: number;
  document_type: "unknown" | "invoice" | "delivery_note";
  document_number?: string | null;
  document_date?: string | null;
  supplier_name?: string | null;
  total_amount?: number | null;
  currency: string;
  summary_text: string;
  extracted_text: string;
  status: "processing" | "ready" | "error";
  matching_status: "pending" | "not_started" | "ready_for_match";
  review_status: "to_review" | "reviewed";
  error_detail?: string | null;
  created_at: string;
  updated_at: string;
}

export interface FiscalDocumentsListResponse {
  items: FiscalDocumentRead[];
  total_count: number;
  invoice_count: number;
  delivery_note_count: number;
  to_review_count: number;
}

export interface FiscalDocumentSettingsResponse {
  inbound_email?: string | null;
  mailbox_configured: boolean;
  updated_at?: string | null;
}

export interface FiscalDocumentSettingsRequest {
  inbound_email?: string | null;
}

export interface FiscalDocumentInboxStatusResponse {
  mailbox_configured: boolean;
  inbound_email?: string | null;
  google_configured: boolean;
  google_connected: boolean;
  google_account_email?: string | null;
  gmail_scope_granted: boolean;
  mailbox_matches_google_account: boolean;
  ready_for_sync: boolean;
  next_step: string;
}

export interface FiscalDocumentInboxItemResponse {
  id: string;
  message_id: string;
  attachment_id: string;
  subject: string;
  sender?: string | null;
  received_at?: string | null;
  attachment_name: string;
  mime_type: string;
  sync_status: "imported" | "unsupported" | "error";
  document_id?: string | null;
  error_detail?: string | null;
  created_at: string;
  updated_at: string;
}

export interface FiscalDocumentInboxListResponse {
  items: FiscalDocumentInboxItemResponse[];
  total_count: number;
  imported_count: number;
  unsupported_count: number;
  error_count: number;
}

type ApiErrorPayload = {
  detail?: unknown;
  message?: unknown;
};

const AUTH_FIELD_LABELS: Record<string, string> = {
  locale_name: "Nome locale",
  address: "Indirizzo",
  phone_number: "Telefono",
  whatsapp_number: "WhatsApp",
  admin_name: "Nome amministratore",
  username: "Username admin",
  email: "Email admin",
  password: "Password amministratore",
  identifier: "Username o email"
};

function buildHeaders(includeAuth = true): HeadersInit {
  const headers = new Headers(DEFAULT_HEADERS);
  if (includeAuth) {
    const token = getStoredSessionToken();
    if (token) {
      headers.set("Authorization", `Bearer ${token}`);
    }
  }
  return headers;
}

function buildUploadHeaders(includeAuth = true): Headers {
  const headers = new Headers();
  if (includeAuth) {
    const token = getStoredSessionToken();
    if (token) {
      headers.set("Authorization", `Bearer ${token}`);
    }
  }
  return headers;
}

function readFieldLabel(detail: Record<string, unknown>): string | null {
  const location = detail.loc;
  if (!Array.isArray(location)) {
    return null;
  }

  const fieldKey = location
    .filter((segment): segment is string => typeof segment === "string" && segment !== "body")
    .at(-1);

  if (!fieldKey) {
    return null;
  }

  return AUTH_FIELD_LABELS[fieldKey] ?? fieldKey;
}

function translateValidationMessage(detail: Record<string, unknown>): string | null {
  const type = typeof detail.type === "string" ? detail.type : "";
  const message = typeof detail.msg === "string" ? detail.msg.trim() : "";
  const context = detail.ctx && typeof detail.ctx === "object" ? (detail.ctx as Record<string, unknown>) : null;

  if (type === "missing" || message === "Field required") {
    return "campo obbligatorio.";
  }

  if (type === "string_too_short") {
    const minLength = typeof context?.min_length === "number" ? context.min_length : null;
    return minLength ? `inserisci almeno ${minLength} caratteri.` : "il valore inserito e troppo corto.";
  }

  if (type === "string_too_long") {
    const maxLength = typeof context?.max_length === "number" ? context.max_length : null;
    return maxLength ? `non puo superare ${maxLength} caratteri.` : "il valore inserito e troppo lungo.";
  }

  if (type === "string_type") {
    return "inserisci un testo valido.";
  }

  if (type === "value_error") {
    return message || null;
  }

  if (message) {
    return message;
  }

  return null;
}

function normalizeErrorDetail(detail: unknown, fallback: string): string {
  if (typeof detail === "string") {
    const message = detail.trim();
    return message || fallback;
  }

  if (Array.isArray(detail)) {
    const messages = detail
      .map((item) => normalizeErrorDetail(item, ""))
      .map((message) => message.trim())
      .filter(Boolean);

    return messages.length > 0 ? messages.join(" ") : fallback;
  }

  if (detail && typeof detail === "object") {
    const record = detail as Record<string, unknown>;

    if ("detail" in record) {
      return normalizeErrorDetail(record.detail, fallback);
    }

    if ("message" in record && typeof record.message === "string" && record.message.trim()) {
      return record.message.trim();
    }

    const translatedMessage = translateValidationMessage(record);
    const fieldLabel = readFieldLabel(record);
    if (translatedMessage) {
      return fieldLabel ? `${fieldLabel}: ${translatedMessage}` : translatedMessage;
    }
  }

  return fallback;
}

async function readErrorDetail(response: Response, fallback: string): Promise<string> {
  if (response.ok) {
    return fallback;
  }

  try {
    const errorPayload = (await response.json()) as ApiErrorPayload;
    const normalized = normalizeErrorDetail(errorPayload.detail ?? errorPayload.message, fallback);
    if (normalized) {
      return normalized;
    }
  } catch {
    // Ignore parsing failures and keep the fallback error.
  }

  return fallback;
}

async function parseAuthResponse(response: Response, fallbackMessage: string): Promise<AuthResponse> {
  const payload = (await response.json()) as Partial<AuthResponse> & ApiErrorPayload;

  if (!response.ok || !payload.success || !payload.session_token || !payload.current_user || !payload.tenant_context) {
    throw new Error(normalizeErrorDetail(payload.detail ?? payload.message, fallbackMessage));
  }

  return payload as AuthResponse;
}

export async function fetchBackendHealth(baseUrl: string): Promise<BackendHealthResponse> {
  const response = await fetch(`${baseUrl}/health`, {
    headers: buildHeaders(false)
  });

  if (!response.ok) {
    throw new Error(`Backend hub non raggiungibile (${response.status})`);
  }

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

export async function fetchFiscalDocumentSettings(baseUrl: string): Promise<FiscalDocumentSettingsResponse> {
  const response = await fetch(`${baseUrl}/fiscal-documents/settings`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Impostazioni documenti fiscali non disponibili (${response.status})`));
  }

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

export async function updateFiscalDocumentSettings(
  baseUrl: string,
  payload: FiscalDocumentSettingsRequest
): Promise<FiscalDocumentSettingsResponse> {
  const response = await fetch(`${baseUrl}/fiscal-documents/settings`, {
    method: "PUT",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Salvataggio mailbox documenti fiscali non riuscito."));
  }

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

export async function fetchFiscalDocumentInboxStatus(baseUrl: string): Promise<FiscalDocumentInboxStatusResponse> {
  const response = await fetch(`${baseUrl}/fiscal-documents/inbox-status`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Stato inbox documenti fiscali non disponibile (${response.status})`));
  }

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

export async function fetchFiscalDocumentInbox(baseUrl: string): Promise<FiscalDocumentInboxListResponse> {
  const response = await fetch(`${baseUrl}/fiscal-documents/inbox`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Inbox documenti fiscali non disponibile (${response.status})`));
  }

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

export async function syncFiscalDocumentInbox(baseUrl: string): Promise<FiscalDocumentInboxListResponse> {
  const response = await fetch(`${baseUrl}/fiscal-documents/inbox/sync`, {
    method: "POST",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Sincronizzazione inbox documenti fiscali non riuscita."));
  }

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

export async function fetchBackendCatalog(baseUrl: string): Promise<BackendCatalogResponse> {
  const response = await fetch(`${baseUrl}/modules/catalog`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(`Catalogo moduli non disponibile (${response.status})`);
  }

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

export async function fetchAuthStatus(baseUrl: string): Promise<AuthStatusResponse> {
  const response = await fetch(`${baseUrl}/auth/status`, {
    headers: buildHeaders(false)
  });

  if (!response.ok) {
    throw new Error(`Stato autenticazione non disponibile (${response.status})`);
  }

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

export async function registerTenant(baseUrl: string, payload: RegisterTenantRequest): Promise<AuthResponse> {
  const response = await fetch(`${baseUrl}/auth/register`, {
    method: "POST",
    headers: buildHeaders(false),
    body: JSON.stringify(payload)
  });

  return parseAuthResponse(response, "Registrazione del locale non riuscita.");
}

export async function bootstrapSuperAdmin(baseUrl: string, payload: BootstrapSuperAdminRequest): Promise<AuthResponse> {
  const response = await fetch(`${baseUrl}/auth/bootstrap-super-admin`, {
    method: "POST",
    headers: buildHeaders(false),
    body: JSON.stringify(payload)
  });

  return parseAuthResponse(response, "Configurazione iniziale del super admin non riuscita.");
}

export async function loginToPortal(baseUrl: string, payload: AuthPayload): Promise<AuthResponse> {
  const response = await fetch(`${baseUrl}/auth/login`, {
    method: "POST",
    headers: buildHeaders(false),
    body: JSON.stringify(payload)
  });

  return parseAuthResponse(response, "Credenziali non valide.");
}

export async function fetchAuthProfile(baseUrl: string): Promise<AuthResponse> {
  const response = await fetch(`${baseUrl}/auth/me`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Sessione non valida (${response.status})`));
  }

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

export async function logoutFromPortal(baseUrl: string): Promise<void> {
  const response = await fetch(`${baseUrl}/auth/logout`, {
    method: "POST",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Logout fallito (${response.status})`));
  }
}

export async function fetchTenantUsers(baseUrl: string): Promise<TenantStaffUser[]> {
  const response = await fetch(`${baseUrl}/auth/tenant-users`, {
    method: "GET",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Elenco account non disponibile (${response.status})`));
  }

  const payload = (await response.json()) as { users?: TenantStaffUser[] };
  return payload.users ?? [];
}

export async function createTenantUser(baseUrl: string, payload: TenantStaffUserRequest): Promise<TenantStaffUser> {
  const response = await fetch(`${baseUrl}/auth/tenant-users`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Creazione account non riuscita (${response.status})`));
  }

  const body = (await response.json()) as { user: TenantStaffUser };
  return body.user;
}

export async function updateTenantUser(
  baseUrl: string,
  userId: string,
  payload: TenantStaffUserRequest
): Promise<TenantStaffUser> {
  const response = await fetch(`${baseUrl}/auth/tenant-users/${userId}`, {
    method: "PUT",
    headers: buildHeaders(),
    body: JSON.stringify({
      ...payload,
      password: payload.password?.trim() || undefined
    })
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Aggiornamento account non riuscito (${response.status})`));
  }

  const body = (await response.json()) as { user: TenantStaffUser };
  return body.user;
}

export async function deleteTenantUser(baseUrl: string, userId: string): Promise<void> {
  const response = await fetch(`${baseUrl}/auth/tenant-users/${userId}`, {
    method: "DELETE",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Eliminazione account non riuscita (${response.status})`));
  }
}

export async function updateCurrentUserPassword(baseUrl: string, payload: UpdatePasswordRequest): Promise<void> {
  const response = await fetch(`${baseUrl}/auth/me/password`, {
    method: "PUT",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Cambio password non riuscito (${response.status})`));
  }
}

export async function fetchTimeclockStatus(baseUrl: string): Promise<TimeclockStatusResponse> {
  const response = await fetch(`${baseUrl}/timeclock/status`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Stato cartellino non disponibile (${response.status})`));
  }

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

export async function startTimeclockShift(baseUrl: string): Promise<TimeclockStatusResponse> {
  const response = await fetch(`${baseUrl}/timeclock/start`, {
    method: "POST",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Avvio turno non riuscito."));
  }

  return fetchTimeclockStatus(baseUrl);
}

export async function stopTimeclockShift(baseUrl: string): Promise<TimeclockStatusResponse> {
  const response = await fetch(`${baseUrl}/timeclock/stop`, {
    method: "POST",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Chiusura turno non riuscita."));
  }

  return fetchTimeclockStatus(baseUrl);
}

export async function fetchTimeclockOverview(
  baseUrl: string,
  filters: {
    user_id?: string;
    start_date?: string;
    end_date?: string;
    limit?: number;
  } = {}
): Promise<TimeclockOverviewResponse> {
  const params = new URLSearchParams();
  if (filters.user_id?.trim()) {
    params.set("user_id", filters.user_id.trim());
  }
  if (filters.start_date?.trim()) {
    params.set("start_date", filters.start_date.trim());
  }
  if (filters.end_date?.trim()) {
    params.set("end_date", filters.end_date.trim());
  }
  if (filters.limit != null) {
    params.set("limit", String(filters.limit));
  }

  const query = params.toString();
  const response = await fetch(`${baseUrl}/timeclock/overview${query ? `?${query}` : ""}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Riepilogo cartellino non disponibile (${response.status})`));
  }

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

export async function fetchInventoryWarehouses(baseUrl: string): Promise<InventoryWarehouseListResponse> {
  const response = await fetch(`${baseUrl}/inventory/warehouses`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Inventario non disponibile (${response.status})`));
  }

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

export async function fetchInventorySnapshots(baseUrl: string): Promise<InventorySnapshotListResponse> {
  const response = await fetch(`${baseUrl}/inventory/snapshots`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Storico inventario non disponibile (${response.status})`));
  }

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

export async function fetchInventoryWarehouseSessions(
  baseUrl: string,
  warehouseId: string
): Promise<InventorySessionListResponse> {
  const response = await fetch(`${baseUrl}/inventory/warehouses/${warehouseId}/sessions`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Storico inventari magazzino non disponibile (${response.status})`));
  }

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

export async function fetchInventoryWarehouseSessionDetail(
  baseUrl: string,
  warehouseId: string,
  sessionId: string
): Promise<InventorySessionDetailResponse> {
  const response = await fetch(`${baseUrl}/inventory/warehouses/${warehouseId}/sessions/${sessionId}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Dettaglio inventario non disponibile (${response.status})`));
  }

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

export async function createInventoryWarehouse(baseUrl: string, payload: { name: string }): Promise<InventoryWarehouse> {
  const response = await fetch(`${baseUrl}/inventory/warehouses`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Creazione magazzino non riuscita."));
  }

  const body = (await response.json()) as { warehouse: InventoryWarehouse };
  return body.warehouse;
}

export async function fetchInventoryWarehouseDetail(
  baseUrl: string,
  warehouseId: string
): Promise<InventoryWarehouseDetailResponse> {
  const response = await fetch(`${baseUrl}/inventory/warehouses/${warehouseId}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Magazzino non disponibile (${response.status})`));
  }

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

export async function searchInventoryProducts(
  baseUrl: string,
  query: string,
  limit = 20
): Promise<InventoryProductSearchResponse> {
  const params = new URLSearchParams();
  if (query.trim()) {
    params.set("q", query.trim());
  }
  params.set("limit", String(limit));
  const queryString = params.toString();
  const response = await fetch(`${baseUrl}/inventory/products/search${queryString ? `?${queryString}` : ""}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Ricerca prodotti inventario non disponibile (${response.status})`));
  }

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

export async function createInventorySnapshot(
  baseUrl: string,
  payload: { snapshot_date?: string | null }
): Promise<{ snapshot: InventorySnapshot; replaced_existing: boolean }> {
  const response = await fetch(`${baseUrl}/inventory/snapshots`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Salvataggio fotografia inventario non riuscito."));
  }

  return response.json() as Promise<{ snapshot: InventorySnapshot; replaced_existing: boolean }>;
}

export async function createInventoryWarehouseSession(
  baseUrl: string,
  warehouseId: string,
  payload: { inventory_date?: string | null }
): Promise<{ session: InventorySession; replaced_existing: boolean }> {
  const response = await fetch(`${baseUrl}/inventory/warehouses/${warehouseId}/sessions`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Salvataggio inventario magazzino non riuscito."));
  }

  return response.json() as Promise<{ session: InventorySession; replaced_existing: boolean }>;
}

export async function fetchInventoryConsumption(
  baseUrl: string,
  filters: {
    start_snapshot_id?: string;
    end_snapshot_id?: string;
  } = {}
): Promise<InventoryConsumptionResponse> {
  const params = new URLSearchParams();
  if (filters.start_snapshot_id?.trim()) {
    params.set("start_snapshot_id", filters.start_snapshot_id.trim());
  }
  if (filters.end_snapshot_id?.trim()) {
    params.set("end_snapshot_id", filters.end_snapshot_id.trim());
  }
  const query = params.toString();
  const response = await fetch(`${baseUrl}/inventory/consumption${query ? `?${query}` : ""}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Analisi consumi non disponibile (${response.status})`));
  }

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

export async function fetchInventoryWarehouseConsumption(
  baseUrl: string,
  warehouseId: string,
  filters: {
    start_session_id?: string;
    end_session_id?: string;
  } = {}
): Promise<InventoryConsumptionResponse> {
  const params = new URLSearchParams();
  if (filters.start_session_id?.trim()) {
    params.set("start_session_id", filters.start_session_id.trim());
  }
  if (filters.end_session_id?.trim()) {
    params.set("end_session_id", filters.end_session_id.trim());
  }
  const query = params.toString();
  const response = await fetch(`${baseUrl}/inventory/warehouses/${warehouseId}/consumption${query ? `?${query}` : ""}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Analisi consumi magazzino non disponibile (${response.status})`));
  }

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

export async function addInventoryStock(
  baseUrl: string,
  warehouseId: string,
  payload: {
    product_id: number;
    quantity: number;
    operation?: "add" | "set";
  }
): Promise<InventoryWarehouseDetailResponse> {
  const response = await fetch(`${baseUrl}/inventory/warehouses/${warehouseId}/stock`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, "Carico inventario non riuscito."));
  }

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

export async function updateSuperAdminPassword(
  baseUrl: string,
  payload: UpdateSuperAdminPasswordRequest
): Promise<void> {
  const response = await fetch(`${baseUrl}/auth/super-admin/password`, {
    method: "PUT",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Aggiornamento password admin fallito (${response.status})`));
  }
}

export async function fetchAdminOverview(baseUrl: string): Promise<AdminOverviewResponse> {
  const response = await fetch(`${baseUrl}/admin/overview`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Pannello admin non disponibile (${response.status})`));
  }

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

export async function createAdminTenant(baseUrl: string, payload: AdminTenantRequest): Promise<AdminTenantSummary> {
  const response = await fetch(`${baseUrl}/admin/tenants`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify({ ...payload, password: payload.password ?? "" })
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Creazione locale fallita (${response.status})`));
  }

  const data = (await response.json()) as { success?: boolean; tenant?: AdminTenantSummary };
  if (!data.success || !data.tenant) {
    throw new Error("Creazione locale fallita.");
  }

  return data.tenant;
}

export async function updateAdminTenant(
  baseUrl: string,
  tenantId: string,
  payload: AdminTenantRequest
): Promise<AdminTenantSummary> {
  const response = await fetch(`${baseUrl}/admin/tenants/${tenantId}`, {
    method: "PUT",
    headers: buildHeaders(),
    body: JSON.stringify({ ...payload, password: payload.password?.trim() || undefined })
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Aggiornamento locale fallito (${response.status})`));
  }

  const data = (await response.json()) as { success?: boolean; tenant?: AdminTenantSummary };
  if (!data.success || !data.tenant) {
    throw new Error("Aggiornamento locale fallito.");
  }

  return data.tenant;
}

export async function impersonateTenant(baseUrl: string, tenantId: string): Promise<AuthResponse> {
  const response = await fetch(`${baseUrl}/admin/tenants/${tenantId}/impersonate`, {
    method: "POST",
    headers: buildHeaders()
  });

  return parseAuthResponse(response, "Ingresso nel locale non riuscito.");
}

export async function fetchAssistantProfile(baseUrl: string): Promise<AssistantProfileResponse> {
  const response = await fetch(`${baseUrl}/llm/assistant-profile`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(`Profilo assistente non disponibile (${response.status})`);
  }

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

export async function sendAssistantMessage(
  baseUrl: string,
  payload: AssistantChatRequest
): Promise<AssistantChatResponse> {
  const response = await fetch(`${baseUrl}/llm/chat`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    let detail = `Assistente non disponibile (${response.status})`;
    try {
      const errorPayload = (await response.json()) as { detail?: string };
      if (errorPayload.detail) {
        detail = errorPayload.detail;
      }
    } catch {
      // Ignore parsing failures and keep the fallback error.
    }
    throw new Error(detail);
  }

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

export async function fetchAssistantThread(baseUrl: string, threadId?: string | null): Promise<AssistantThreadResponse> {
  const searchParams = new URLSearchParams();
  if (threadId) {
    searchParams.set("thread_id", threadId);
  }
  const suffix = searchParams.toString() ? `?${searchParams.toString()}` : "";
  const response = await fetch(`${baseUrl}/llm/chat/thread${suffix}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Thread assistente non disponibile (${response.status})`));
  }

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

export async function clearAssistantThread(baseUrl: string, threadId?: string | null): Promise<void> {
  const searchParams = new URLSearchParams();
  if (threadId) {
    searchParams.set("thread_id", threadId);
  }
  const suffix = searchParams.toString() ? `?${searchParams.toString()}` : "";
  const response = await fetch(`${baseUrl}/llm/chat/thread${suffix}`, {
    method: "DELETE",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Pulizia chat non riuscita (${response.status})`));
  }
}

export async function fetchMenuPromptSettings(baseUrl: string): Promise<MenuPromptSettings> {
  const response = await fetch(`${baseUrl}/llm/menu-settings`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Configurazione menu non disponibile (${response.status})`));
  }

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

export async function updateMenuPromptSettings(
  baseUrl: string,
  payload: MenuPromptSettingsPayload
): Promise<MenuPromptSettings> {
  const response = await fetch(`${baseUrl}/llm/menu-settings`, {
    method: "PUT",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Salvataggio configurazione menu fallito (${response.status})`));
  }

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

export async function fetchGoogleWorkspaceStatus(baseUrl: string): Promise<GoogleWorkspaceStatusResponse> {
  const response = await fetch(`${baseUrl}/google-workspace/status`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Stato Google Workspace non disponibile (${response.status})`));
  }

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

export async function startGoogleWorkspaceAuthorization(
  baseUrl: string,
  returnTo = "/documents",
  scopeProfile?: string
): Promise<GoogleWorkspaceAuthorizationResponse> {
  const query = new URLSearchParams({ return_to: returnTo });
  if (scopeProfile) {
    query.set("scope_profile", scopeProfile);
  }
  const response = await fetch(`${baseUrl}/google-workspace/oauth/start?${query.toString()}`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Avvio autorizzazione Google fallito (${response.status})`));
  }

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

export async function disconnectGoogleWorkspace(baseUrl: string): Promise<void> {
  const response = await fetch(`${baseUrl}/google-workspace/disconnect`, {
    method: "POST",
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Disconnessione Google fallita (${response.status})`));
  }
}

export async function generateGoogleWorkspacePreview(
  baseUrl: string,
  payload: GoogleWorkspacePreviewRequest
): Promise<GoogleWorkspaceDocumentPreview> {
  const response = await fetch(`${baseUrl}/google-workspace/preview`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Preview documento non disponibile (${response.status})`));
  }

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

export async function createGoogleWorkspaceDocument(
  baseUrl: string,
  payload: GoogleWorkspaceCreateRequest
): Promise<GoogleWorkspaceCreateResponse> {
  const response = await fetch(`${baseUrl}/google-workspace/create`, {
    method: "POST",
    headers: buildHeaders(),
    body: JSON.stringify(payload)
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Creazione documento Google fallita (${response.status})`));
  }

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

export async function fetchFiscalDocuments(baseUrl: string): Promise<FiscalDocumentsListResponse> {
  const response = await fetch(`${baseUrl}/fiscal-documents`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Archivio fiscale non disponibile (${response.status})`));
  }

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

export async function uploadFiscalDocuments(baseUrl: string, files: File[]): Promise<FiscalDocumentsListResponse> {
  const formData = new FormData();
  files.forEach((file) => formData.append("files", file));

  const response = await fetch(`${baseUrl}/fiscal-documents/upload`, {
    method: "POST",
    headers: buildUploadHeaders(),
    body: formData
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Caricamento documenti fiscali fallito (${response.status})`));
  }

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

export async function downloadFiscalDocument(baseUrl: string, documentId: string): Promise<Blob> {
  const response = await fetch(`${baseUrl}/fiscal-documents/${documentId}/download`, {
    headers: buildHeaders()
  });

  if (!response.ok) {
    throw new Error(await readErrorDetail(response, `Download documento fiscale non riuscito (${response.status})`));
  }

  return response.blob();
}
