import { Hono } from 'hono';
import { z } from 'zod';

import { getIphotoStats, ingestAlbums, ingestPhotos, listPendingUploads, storePhotoBlob } from '@/features/iphoto';
import { withSyncHistory } from '@/shared/sync-history';

const photoSchema = z.object({
  localIdentifier: z.string().min(1),
  mediaType: z.enum(['image', 'video', 'live_photo', 'audio']),
  width: z.number(),
  height: z.number(),
  fileSize: z.number().nullish(),
  durationSeconds: z.number().nullish(),
  capturedAt: z.string(),
  modifiedAt: z.string().nullish(),
  originalFilename: z.string().nullish(),
  mimeType: z.string().nullish(),
  latitude: z.number().nullish(),
  longitude: z.number().nullish(),
  locationName: z.string().nullish(),
  isFavorite: z.boolean().nullish(),
  isHidden: z.boolean().nullish(),
  isScreenshot: z.boolean().nullish(),
  isSelfie: z.boolean().nullish(),
  isBurst: z.boolean().nullish(),
  burstIdentifier: z.string().nullish(),
  exif: z.record(z.unknown()).nullish(),
  contentHash: z.string().nullish(),
});

const syncPhotosSchema = z.object({
  photos: z.array(photoSchema),
});

const albumSchema = z.object({
  localIdentifier: z.string().min(1),
  title: z.string().min(1),
  albumType: z.enum(['user', 'smart', 'shared', 'system']),
  photoCount: z.number().nullish(),
  photoLocalIdentifiers: z.array(z.string()).nullish(),
  coverPhotoLocalIdentifier: z.string().nullish(),
  startDate: z.string().nullish(),
  endDate: z.string().nullish(),
  sortOrder: z.number().nullish(),
});

const syncAlbumsSchema = z.object({
  albums: z.array(albumSchema),
});

const localIdParam = z.string().min(1);

export const iphotoClientRouter = new Hono()
  .get('/stats', async (c) => {
    const deviceId = c.get('deviceId');
    const stats = await getIphotoStats(deviceId);
    return c.json({ success: true, data: stats });
  })
  .get('/upload/pending', async (c) => {
    const deviceId = c.get('deviceId');
    const limitParam = c.req.query('limit');
    const parsed = limitParam ? Number(limitParam) : NaN;
    const limit = Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, 1000) : 500;
    const photos = await listPendingUploads(deviceId, limit);
    return c.json({ success: true, data: { localIdentifiers: photos.map((p) => p.localIdentifier) } });
  })
  .post('/sync', async (c) => {
    const deviceId = c.get('deviceId');
    const payload = syncPhotosSchema.parse(await c.req.json());
    const result = await withSyncHistory(deviceId, 'photos', () => ingestPhotos(deviceId, payload));
    return c.json({ success: true, data: result });
  })
  .post('/albums', async (c) => {
    const deviceId = c.get('deviceId');
    const payload = syncAlbumsSchema.parse(await c.req.json());
    const result = await withSyncHistory(deviceId, 'photos', () => ingestAlbums(deviceId, payload));
    return c.json({ success: true, data: result });
  })
  .post('/upload/:localIdentifier', async (c) => {
    const deviceId = c.get('deviceId');
    const localId = localIdParam.parse(c.req.param('localIdentifier'));
    const contentType = c.req.header('content-type') ?? 'application/octet-stream';
    const filename = c.req.header('x-filename') ?? localId;

    const body = c.req.raw.body;
    if (!body) {
      return c.json({ error: 'no_body', code: 'bad_request' }, 400);
    }

    const result = await storePhotoBlob(deviceId, localId, contentType, filename, body);
    return c.json({ success: true, data: result });
  });
