import { ApiError } from '@/types';

/**
 * All requests go to /api/* (relative paths) — the Next.js catch-all
 * route handler proxies them to the backend. This keeps all traffic
 * within the same origin, avoiding CORS preflights entirely.
 */

async function request<T>(method: string, path: string, body?: unknown): Promise<T> {
  const res = await fetch(path, {
    method,
    headers: { 'Content-Type': 'application/json' },
    body: body != null ? JSON.stringify(body) : undefined,
    credentials: 'include',
  });

  if (res.status === 401) {
    if (typeof window !== 'undefined') {
      window.location.href = '/login';
    }
    throw new ApiError(401, 'UNAUTHORIZED', 'Authentication required');
  }

  if (res.status === 403) {
    throw new ApiError(403, 'FORBIDDEN', 'Insufficient permissions');
  }

  if (!res.ok) {
    const body = await res.json().catch(() => ({ message: 'Request failed' }));
    const envelope = body as { code?: string; message?: string; error?: { code?: string; message?: string } };
    const error = envelope.error ?? envelope;
    throw new ApiError(
      res.status,
      error.code ?? 'REQUEST_FAILED',
      error.message ?? 'Request failed',
    );
  }

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

export const api = {
  get: <T>(path: string) => request<T>('GET', path),
  post: <T>(path: string, body?: unknown) => request<T>('POST', path, body),
  patch: <T>(path: string, body?: unknown) => request<T>('PATCH', path, body),
  put: <T>(path: string, body?: unknown) => request<T>('PUT', path, body),
  delete: <T>(path: string) => request<T>('DELETE', path),
};

// ── Auth ──────────────────────────────────────────────────────────────────────

// FIX-14: admin panel auth resolves through the backoffice endpoint.
const BACKOFFICE_AUTH_BASE = '/api/backoffice/auth';

export const authApi = {
  login: (email: string, password: string) =>
    api.post<{ id: string; email: string; role: string }>(`${BACKOFFICE_AUTH_BASE}/login`, { email, password }),
  logout: () => api.post(`${BACKOFFICE_AUTH_BASE}/logout`),
  me: () =>
    api.get<{ id: string; email: string; role: string } | { user: null }>(`${BACKOFFICE_AUTH_BASE}/me`),
};

// ── Products ──────────────────────────────────────────────────────────────────
// Backend: /catalog/products (admin list), /products/:id (admin CRUD)

export const productsApi = {
  list: (params?: { limit?: number; offset?: number; q?: string }) => {
    const sp = new URLSearchParams();
    if (params?.limit) sp.set('limit', String(params.limit));
    if (params?.offset) sp.set('offset', String(params.offset));
    if (params?.q) sp.set('q', params.q);
    const qs = sp.toString();
    return api.get<{ items: import('@/types').Product[]; total: number }>(
      `/api/catalog/products${qs ? `?${qs}` : ''}`,
    );
  },
  get: (id: string) => api.get<import('@/types').Product>(`/api/products/${id}`),
  getVariants: (id: string) =>
    api.get<{ items: import('@/types').ProductVariant[] }>(`/api/products/${id}/variants`),
  createVariant: (productId: string, data: { sku: string; ean?: string | null }) =>
    api.post<import('@/types').ProductVariant>(`/api/products/${productId}/variants`, data),
  create: (data: unknown) => api.post<import('@/types').Product>('/api/products', data),
  update: (id: string, data: unknown) =>
    api.patch<import('@/types').Product>(`/api/products/${id}`, data),
  generateSeo: (id: string) =>
    api.post<import('@/types').Product>(`/api/products/${id}/generate-seo`),
  setState: (id: string, state: 'active' | 'archived') =>
    api.patch(`/api/products/${id}/state`, { state }),
  delete: (id: string) => api.delete(`/api/products/${id}`),
  updateVariant: (productId: string, variantId: string, data: unknown) =>
    api.patch<import('@/types').ProductVariant>(`/api/products/${productId}/variants/${variantId}`, data),
};

// ── Orders ────────────────────────────────────────────────────────────────────

export const ordersApi = {
  list: (params?: { limit?: number; offset?: number; status?: string; q?: string }) => {
    const sp = new URLSearchParams();
    if (params?.limit) sp.set('limit', String(params.limit));
    if (params?.offset) sp.set('offset', String(params.offset));
    if (params?.status) sp.set('status', params.status);
    if (params?.q) sp.set('q', params.q);
    const qs = sp.toString();
    return api.get<{ items: import('@/types').Order[]; total: number } | import('@/types').Order[]>(
      `/api/orders${qs ? `?${qs}` : ''}`,
    ).then((data) => (Array.isArray(data) ? { items: data, total: data.length } : data));
  },
  get: (id: string) => api.get<import('@/types').Order>(`/api/orders/${id}/admin`),
  transition: (id: string, state: string, trackingNumber?: string, courier?: string) =>
    api.post<import('@/types').Order & { notified?: boolean; notificationError?: string }>(
      `/api/orders/${id}/transitions/admin`,
      {
        state,
        ...(trackingNumber?.trim() ? { trackingNumber: trackingNumber.trim() } : {}),
        ...(courier?.trim() ? { courier: courier.trim() } : {}),
      },
    ),
  editItems: (id: string, items: { variantId: string; quantity: number }[]) =>
    api.put<import('@/types').Order>(`/api/orders/${id}/items`, { items }),
  updateShipping: (id: string, trackingNumber: string, note?: string, courier?: string) =>
    api.post<import('@/types').Order>(
      `/api/orders/${id}/shipping`,
      {
        trackingNumber,
        ...(courier?.trim() ? { courier: courier.trim() } : {}),
        ...(note?.trim() ? { note } : {}),
      },
    ),
  history: (id: string) =>
    api.get<{ items: import('@/types').OrderHistoryEvent[] }>(`/api/orders/${id}/history`),
};

// ── Customers ─────────────────────────────────────────────────────────────────

export const customersApi = {
  list: (params?: { offset?: number; limit?: number; q?: string }) => {
    const sp = new URLSearchParams();
    if (params?.offset !== undefined) sp.set('offset', String(params.offset));
    if (params?.limit !== undefined) sp.set('limit', String(params.limit));
    if (params?.q) sp.set('q', params.q);
    const qs = sp.toString();
    return api.get<{ items: import('@/types').Customer[]; total: number }>(`/api/users${qs ? `?${qs}` : ''}`);
  },
  get: (id: string) => api.get<import('@/types').Customer>(`/api/users/${id}`),
  update: (id: string, data: { displayName?: string; phone?: string }) =>
    api.patch<import('@/types').Customer>(`/api/users/${id}`, data),
  create: (data: { email: string; password: string; displayName?: string; phone?: string }) =>
    api.post<import('@/types').Customer>('/api/auth/register', data),
  sendPasswordResetLink: (email: string) =>
    api.post<{ ok: boolean }>('/api/auth/password-reset/request', { email }),
  // ── Direcciones (FIX-18) ───────────────────────────────────────────────────
  listAddresses: (id: string) =>
    api.get<{ items: import('@/types').Address[] }>(`/api/users/${id}/addresses`),
  createAddress: (id: string, data: Omit<import('@/types').Address, 'id' | 'userId' | 'createdAt' | 'updatedAt'>) =>
    api.post<import('@/types').Address>(`/api/users/${id}/addresses`, data),
  updateAddress: (id: string, addressId: string, data: Partial<Omit<import('@/types').Address, 'id' | 'userId' | 'createdAt' | 'updatedAt'>>) =>
    api.patch<import('@/types').Address>(`/api/users/${id}/addresses/${addressId}`, data),
  deleteAddress: (id: string, addressId: string) =>
    api.delete<void>(`/api/users/${id}/addresses/${addressId}`),
};

// ── Brands ────────────────────────────────────────────────────────────────────

export const brandsApi = {
  list: () => api.get<{ items: import('@/types').Brand[] }>('/api/brands'),
  create: (data: unknown) => api.post<import('@/types').Brand>('/api/brands', data),
  update: (id: string, data: unknown) =>
    api.patch<import('@/types').Brand>(`/api/brands/${id}`, data),
  delete: (id: string) => api.delete<void>(`/api/brands/${id}`),
};

// ── Categories ────────────────────────────────────────────────────────────────

export const categoriesApi = {
  list: () => api.get<{ items: import('@/types').Category[] }>('/api/categories/tree'),
  create: (data: unknown) => api.post<import('@/types').Category>('/api/categories', data),
  update: (id: string, data: unknown) =>
    api.patch<import('@/types').Category>(`/api/categories/${id}`, data),
  generateSeo: (id: string) =>
    api.post<import('@/types').Category>(`/api/categories/${id}/generate-seo`),
  delete: (id: string) => api.delete<void>(`/api/categories/${id}`),
};

// ── Inventory ─────────────────────────────────────────────────────────────────

export const inventoryApi = {
  getAvailability: (variantId: string) =>
    api.get<import('@/types').StockAvailability>(`/api/inventory/${variantId}/availability`),
  setStock: (id: string, quantity: number) =>
    api.put<import('@/types').StockItem>(`/api/inventory/${id}/stock`, { quantity }),
};

// ── Pricing ───────────────────────────────────────────────────────────────────

export const pricingApi = {
  getVariantPrice: (id: string) => api.get<import('@/types').VariantPrice>(`/api/pricing/variants/${id}`),
  setVariantPrice: (
    id: string,
    netUnitAmountCents: number,
    vatRate: 'general' | 'reduced' | 'super-reduced',
    offerCents?: number | null,
    costCents?: number | null,
  ) =>
    api.put<import('@/types').VariantPrice>(`/api/pricing/variants/${id}`, {
      netUnitAmountCents,
      vatRate,
      offerCents: offerCents ?? null,
      costCents: costCents ?? null,
    }),
};

// ── Promotions ────────────────────────────────────────────────────────────────

export const promotionsApi = {
  list: () => api.get<{ items: unknown[] }>('/api/promotions'),
  create: (data: unknown) => api.post('/api/promotions', data),
  update: (code: string, data: unknown) => api.patch(`/api/promotions/${code}`, data),
  delete: (code: string) => api.delete(`/api/promotions/${code}`),
};

// ── Reviews ───────────────────────────────────────────────────────────────────

export const reviewsApi = {
  listAdmin: (params?: { status?: string; limit?: number; offset?: number }) => {
    const sp = new URLSearchParams();
    if (params?.status) sp.set('status', params.status);
    if (params?.limit) sp.set('limit', String(params.limit));
    if (params?.offset) sp.set('offset', String(params.offset));
    const qs = sp.toString();
    return api.get<{ items: unknown[]; total: number }>(`/api/reviews/admin${qs ? `?${qs}` : ''}`);
  },
  moderate: (id: string, status: 'published' | 'rejected') =>
    api.patch(`/api/reviews/${id}/moderate`, { status }),
};

// ── CMS ───────────────────────────────────────────────────────────────────────

export const cmsApi = {
  list: () => api.get<{ items: unknown[] }>('/api/cms/pages'),
  get: (slug: string) => api.get(`/api/cms/pages/${slug}`),
  create: (data: unknown) => api.post('/api/cms/pages', data),
  update: (id: string, data: unknown) => api.patch(`/api/cms/pages/${id}`, data),
  publish: (id: string) => api.post(`/api/cms/pages/${id}/publish`, {}),
  unpublish: (id: string) => api.post(`/api/cms/pages/${id}/unpublish`, {}),
};

// ── Admin Users ─────────────────────────────────────────────────────────────────

export const adminUsersApi = {
  list: (params?: { limit?: number; offset?: number; role?: string; q?: string }) => {
    const sp = new URLSearchParams();
    if (params?.limit) sp.set('limit', String(params.limit));
    if (params?.offset) sp.set('offset', String(params.offset));
    if (params?.role) sp.set('role', params.role);
    if (params?.q) sp.set('q', params.q);
    const qs = sp.toString();
    return api.get<{ items: { id: string; email: string; role: string; createdAt: string }[]; total: number }>(
      `/api/admin/users${qs ? `?${qs}` : ''}`,
    );
  },
  create: (data: { email: string; password: string; role: string }) =>
    api.post<{ id: string; email: string; role: string; createdAt: string }>('/api/admin/users', data),
  update: (id: string, data: { role?: string; password?: string }) =>
    api.patch<{ id: string; email: string; role: string; createdAt: string }>(`/api/admin/users/${id}`, data),
  delete: (id: string) => api.delete<void>(`/api/admin/users/${id}`),
};

// ── Tax Rates ────────────────────────────────────────────────────────────────────

export interface TaxRate {
  id: string; name: string; ratePercent: number; country: string; appliesTo: string; active: boolean;
}
export const taxApi = {
  list: () => api.get<{ items: TaxRate[] }>('/api/admin/tax-rates'),
  update: (id: string, data: Partial<{ name: string; ratePercent: number; active: boolean; appliesTo: 'general' | 'reduced' | 'super-reduced' }>) =>
    api.patch('/api/admin/tax-rates/' + id, data),
};

// ── Payments ──────────────────────────────────────────────────────────────────────

export interface PaymentTransaction {
  id: string; provider: string; providerPaymentId: string | null;
  orderId: string | null; amountCents: number; currency: string;
  status: string; raw: unknown; createdAt: string;
}
export const paymentsApi = {
  list: (params?: { limit?: number; offset?: number; status?: string; q?: string }) => {
    const sp = new URLSearchParams();
    if (params?.limit) sp.set('limit', String(params.limit));
    if (params?.offset) sp.set('offset', String(params.offset));
    if (params?.status) sp.set('status', params.status);
    if (params?.q) sp.set('q', params.q);
    const qs = sp.toString();
    return api.get<{ items: PaymentTransaction[]; total: number }>(`/api/admin/payments${qs ? `?${qs}` : ''}`);
  },
  refund: (id: string) => api.post<{ ok: boolean }>(`/api/admin/payments/${id}/refund`, {}),
};

// ── Shipping ───────────────────────────────────────────────────────────────────────

export interface ShippingZone {
  id: string; name: string; country: string; postalCodePrefix: string | null; active: boolean;
}
export interface ShippingMethod {
  id: string; zoneId: string; zoneName: string; name: string;
  baseCostCents: number; freeShippingThresholdCents: number | null; description: string | null;
  maxWeightKg: number | null; freeShippingMaxWeightKg: number | null; active: boolean;
}
export const shippingApi = {
  listZones: () => api.get<{ items: ShippingZone[] }>('/api/admin/shipping/zones'),
  createZone: (data: { name: string; country: string; postalCodePrefix?: string | null; active?: boolean }) =>
    api.post<{ id: string }>('/api/admin/shipping/zones', data),
  updateZone: (id: string, data: Partial<{ name: string; country: string; postalCodePrefix?: string | null; active: boolean }>) =>
    api.patch('/api/admin/shipping/zones/' + id, data),
  deleteZone: (id: string) => api.delete<void>('/api/admin/shipping/zones/' + id),
  listMethods: () => api.get<{ items: ShippingMethod[] }>('/api/admin/shipping/methods'),
  createMethod: (data: { zoneId: string; name: string; baseCostCents: number; freeShippingThresholdCents?: number | null; description?: string | null; maxWeightKg?: number | null; freeShippingMaxWeightKg?: number | null; active?: boolean }) =>
    api.post<{ id: string }>('/api/admin/shipping/methods', data),
  updateMethod: (id: string, data: Partial<{ name: string; baseCostCents: number; freeShippingThresholdCents?: number | null; description?: string | null; maxWeightKg?: number | null; freeShippingMaxWeightKg?: number | null; active: boolean }>) =>
    api.patch('/api/admin/shipping/methods/' + id, data),
  deleteMethod: (id: string) => api.delete<void>('/api/admin/shipping/methods/' + id),
};

// ── Store Settings ─────────────────────────────────────────────────────────────────

export const auditApi = {
  list: (params?: { actorId?: string; action?: string; limit?: number; offset?: number }) => {
    const sp = new URLSearchParams();
    if (params?.action) sp.set('action', params.action);
    if (params?.limit) sp.set('limit', String(params.limit));
    if (params?.offset) sp.set('offset', String(params.offset));
    const qs = sp.toString();
    return api.get<{ items: AuditEntry[]; total: number }>(`/api/admin/audit${qs ? `?${qs}` : ''}`);
  },
};

export interface AuditEntry {
  id: string;
  actorId: string | null;
  action: string;
  target: string;
  metadata: Record<string, unknown>;
  createdAt: string;
}

export interface StoreSettings {
  storeName: string;
  storeTagline: string;
  contactEmail: string;
  contactPhone: string;
  contactAddress: string;
  footerText: string;
  facebookUrl: string;
  instagramUrl: string;
  aiProvider: string;
  aiBaseUrl: string;
  aiModel: string;
  aiApiKey: string;
  aiApiKeyConfigured?: boolean;
  aiSeoTitlePrompt: string;
  aiSeoDescriptionPrompt: string;
  aiProductDescriptionPrompt: string;
  aiCategoryDescriptionPrompt: string;
  aiCategorySeoTitlePrompt: string;
  aiCategorySeoDescriptionPrompt: string;
  smtpHost: string;
  smtpPort: string;
  smtpSecure: boolean;
  smtpUser: string;
  smtpPass: string;
  smtpPassConfigured?: boolean;
  smtpFrom: string;
  couriers?: string[];
}

export const settingsApi = {
  get: () => api.get<StoreSettings>('/api/admin/settings'),
  update: (data: Partial<StoreSettings>) => api.patch<StoreSettings>('/api/admin/settings', data),
};
