import { fetchApi, API_BASE } from './client';

// Client for the standalone photo-api Go service (photo-api/), reachable
// under /api/photos via the Next rewrite (dev) or nginx (prod).

export type GalleryVisibility = 'public' | 'private' | 'link' | 'ticket';

export interface PhotoGalleryEvent {
  id: string;
  slug: string;
  title: string;
  titleEs?: string;
  startDatetime: string;
  status: string;
}

export interface PhotoGallery {
  id: string;
  slug: string;
  title: string;
  titleEs?: string;
  description?: string;
  descriptionEs?: string;
  eventId?: string;
  visibility: GalleryVisibility;
  coverPhotoId?: string;
  photoCount: number;
  coverUrl?: string;
  createdAt: string;
  updatedAt: string;
  event?: PhotoGalleryEvent;
  // Present on admin responses only:
  shareToken?: string;
  shareUrl?: string;
}

export interface Photo {
  id: string;
  galleryId: string;
  position: number;
  originalFilename?: string;
  contentType: string;
  sizeBytes: number;
  /** Size of the preview variant; absent until the server has measured it. */
  previewSizeBytes?: number;
  width?: number;
  height?: number;
  takenAt?: string;
  status: 'queued' | 'processing' | 'ready' | 'failed';
  lastError?: string;
  createdAt: string;
  urls: {
    thumb?: string;
    preview?: string;
    original: string;
    /**
     * Download endpoints. Unlike `preview`/`original` these always stream
     * same-origin instead of redirecting to S3, so fetch() can read them
     * into a Blob (needed by the mobile share sheet) without CORS.
     * `download` serves the preview and is what the lightbox renders, so
     * saving it hits the HTTP cache instead of the network.
     */
    download?: string;
    downloadOriginal: string;
  };
  // Upload responses only: these bytes were already in the gallery, so nothing
  // was stored and the rest of this object describes the existing photo.
  duplicate?: boolean;
}

export interface CreateGalleryInput {
  title: string;
  titleEs?: string;
  description?: string;
  descriptionEs?: string;
  eventId?: string;
  visibility?: GalleryVisibility;
}

export const photosApi = {
  // Admin (requires admin/organizer token)
  createGallery: (data: CreateGalleryInput) =>
    fetchApi<{ gallery: PhotoGallery }>('/api/photos/galleries', {
      method: 'POST',
      body: JSON.stringify(data),
    }),

  getGalleries: (eventId?: string) => {
    const query = eventId ? `?eventId=${encodeURIComponent(eventId)}` : '';
    return fetchApi<{ galleries: PhotoGallery[] }>(`/api/photos/galleries${query}`);
  },

  getGallery: (id: string) =>
    fetchApi<{ gallery: PhotoGallery; photos: Photo[] }>(`/api/photos/galleries/${id}`),

  updateGallery: (id: string, data: Partial<CreateGalleryInput> & { coverPhotoId?: string }) =>
    fetchApi<{ gallery: PhotoGallery }>(`/api/photos/galleries/${id}`, {
      method: 'PATCH',
      body: JSON.stringify(data),
    }),

  deleteGallery: (id: string) =>
    fetchApi<{ message: string }>(`/api/photos/galleries/${id}`, { method: 'DELETE' }),

  rotateShareToken: (id: string) =>
    fetchApi<{ gallery: PhotoGallery }>(`/api/photos/galleries/${id}/share-token`, {
      method: 'POST',
    }),

  uploadPhoto: async (galleryId: string, file: File) => {
    const formData = new FormData();
    formData.append('files', file);

    // Auth rides on the session cookie (sent same-origin automatically)
    const res = await fetch(`${API_BASE}/api/photos/galleries/${galleryId}/photos`, {
      method: 'POST',
      credentials: API_BASE ? 'include' : 'same-origin',
      body: formData,
    });
    if (!res.ok) {
      const errorData = await res.json().catch(() => ({ error: 'Upload failed' }));
      throw new Error(errorData.error || 'Upload failed');
    }
    return res.json() as Promise<{ photos: Photo[] }>;
  },

  /**
   * Upload with byte-level progress (0..1). fetch() cannot report upload
   * progress, so this uses XMLHttpRequest; used by the admin uploader panel.
   */
  uploadPhotoWithProgress: (
    galleryId: string,
    file: File,
    onProgress: (fraction: number) => void
  ) =>
    new Promise<{ photos: Photo[] }>((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open('POST', `${API_BASE}/api/photos/galleries/${galleryId}/photos`);
      // Auth rides on the session cookie; XHR sends same-origin cookies by
      // default, withCredentials is only needed for a cross-origin API_BASE.
      if (API_BASE) xhr.withCredentials = true;
      xhr.upload.onprogress = (e) => {
        if (e.lengthComputable && e.total > 0) onProgress(e.loaded / e.total);
      };
      xhr.onload = () => {
        try {
          const body = JSON.parse(xhr.responseText || '{}');
          if (xhr.status >= 200 && xhr.status < 300) resolve(body);
          else reject(new Error(body.error || `Upload failed (${xhr.status})`));
        } catch {
          reject(new Error(`Upload failed (${xhr.status})`));
        }
      };
      xhr.onerror = () => reject(new Error('Network error during upload'));
      xhr.onabort = () => reject(new Error('Upload cancelled'));
      const formData = new FormData();
      formData.append('files', file);
      xhr.send(formData);
    }),

  reorderPhotos: (galleryId: string, photoIds: string[]) =>
    fetchApi<{ message: string }>(`/api/photos/galleries/${galleryId}/order`, {
      method: 'PATCH',
      body: JSON.stringify({ photoIds }),
    }),

  deletePhoto: (photoId: string) =>
    fetchApi<{ message: string }>(`/api/photos/photos/${photoId}`, { method: 'DELETE' }),

  retryPhoto: (photoId: string) =>
    fetchApi<{ photo: Photo }>(`/api/photos/photos/${photoId}/retry`, { method: 'POST' }),

  // Viewer (anonymous or member token; share token via query param)
  getPublicGalleries: () =>
    fetchApi<{ galleries: PhotoGallery[] }>('/api/photos/public/galleries'),

  getPublicGallery: (slug: string, token?: string) => {
    const query = token ? `?token=${encodeURIComponent(token)}` : '';
    return fetchApi<{ gallery: PhotoGallery; photos: Photo[] }>(
      `/api/photos/public/galleries/${encodeURIComponent(slug)}${query}`
    );
  },

  /** Newest gallery linked to an event; backs /events/[slug]/gallery. */
  getEventGallery: (eventSlug: string, token?: string) => {
    const query = token ? `?token=${encodeURIComponent(token)}` : '';
    return fetchApi<{ gallery: PhotoGallery; photos: Photo[] }>(
      `/api/photos/public/events/${encodeURIComponent(eventSlug)}/gallery${query}`
    );
  },
};
