import { demoFixtures, type DemoFixtures } from './fixtures';

type DemoConfig = {
  fixtures: DemoFixtures;
};

let enabled = false;
let originalFetch: typeof window.fetch | null = null;
const likeState = new Map<number, number>();

declare global {
  interface Window {
    __FOTOSPIEL_DEMO__?: boolean;
    __FOTOSPIEL_DEMO_ACTIVE__?: boolean;
  }
}

export function shouldEnableGuestDemoMode(): boolean {
  if (typeof window === 'undefined') {
    return false;
  }
  const params = new URLSearchParams(window.location.search);
  if (params.get('demo') === '1') {
    return true;
  }
  if (window.__FOTOSPIEL_DEMO__ === true) {
    return true;
  }
  const attr = document.documentElement?.dataset?.guestDemo;
  return attr === 'true';
}

export function enableGuestDemoMode(config: DemoConfig = { fixtures: demoFixtures }): void {
  if (typeof window === 'undefined' || enabled) {
    return;
  }

  originalFetch = window.fetch.bind(window);
  window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
    const request = new Request(input, init);
    const url = new URL(request.url, window.location.origin);

    const response = handleDemoRequest(url, request, config.fixtures);
    if (response) {
      return response;
    }

    return originalFetch!(request);
  };

  enabled = true;
  window.__FOTOSPIEL_DEMO_ACTIVE__ = true;
  notifyDemoToast();
}

function handleDemoRequest(url: URL, request: Request, fixtures: DemoFixtures): Promise<Response> | null {
  if (!url.pathname.startsWith('/api/')) {
    return null;
  }

  const eventMatch = url.pathname.match(/^\/api\/v1\/events\/([^/]+)(?:\/(.*))?/);
  if (eventMatch) {
    const token = decodeURIComponent(eventMatch[1]);
    const remainder = eventMatch[2] ?? '';
    if (token !== fixtures.token && token !== fixtures.event.slug && token !== 'demo') {
      return null;
    }
    return Promise.resolve(handleDemoEventEndpoint(remainder, request, fixtures));
  }

  const galleryMatch = url.pathname.match(/^\/api\/v1\/gallery\/([^/]+)(?:\/(.*))?/);
  if (galleryMatch) {
    const token = decodeURIComponent(galleryMatch[1]);
    if (token !== fixtures.token && token !== fixtures.event.slug && token !== 'demo') {
      return null;
    }
    const resource = galleryMatch[2] ?? '';
    if (!resource) {
      return Promise.resolve(jsonResponse(fixtures.gallery.meta));
    }
    if (resource.startsWith('photos')) {
      return Promise.resolve(
        jsonResponse({ data: fixtures.gallery.photos, next_cursor: null }, { etag: '"demo-gallery"' })
      );
    }
  }

  if (url.pathname.startsWith('/api/v1/photo-shares/')) {
    return Promise.resolve(jsonResponse(fixtures.share));
  }

  if (url.pathname.startsWith('/api/v1/photos/')) {
    return Promise.resolve(handlePhotoAction(url, request, fixtures));
  }

  return null;
}

function handleDemoEventEndpoint(path: string, request: Request, fixtures: DemoFixtures): Response {
  const [resource, ...rest] = path.split('/').filter(Boolean);
  const method = request.method.toUpperCase();

  switch (resource) {
    case undefined:
      return jsonResponse(fixtures.event);
    case 'stats':
      return jsonResponse(fixtures.stats);
    case 'package':
      return jsonResponse(fixtures.eventPackage);
    case 'tasks':
      if (method === 'GET') {
        return jsonResponse(fixtures.tasks, { etag: '"demo-tasks"' });
      }
      return blockedResponse('Aufgaben können in der Demo nicht geändert werden.');
    case 'photos':
      if (method === 'GET') {
        return jsonResponse({ data: fixtures.photos, latest_photo_at: fixtures.photos[0]?.created_at ?? null }, {
          etag: '"demo-photos"',
        });
      }
      if (method === 'POST') {
        return blockedResponse('Uploads sind in der Demo deaktiviert.');
      }
      break;
    case 'upload':
      return blockedResponse('Uploads sind in der Demo deaktiviert.');
    case 'achievements':
      return jsonResponse(fixtures.achievements, { etag: '"demo-achievements"' });
    case 'emotions':
      return jsonResponse(fixtures.emotions, { etag: '"demo-emotions"' });
    case 'notifications':
      if (rest.length >= 2) {
        return new Response(null, { status: 204 });
      }
      return jsonResponse({ data: fixtures.notifications, meta: { unread_count: 1 } }, { etag: '"demo-notifications"' });
    case 'push-subscriptions':
      return new Response(null, { status: 204 });
    default:
      break;
  }

  return jsonResponse({ demo: true });
}

function handlePhotoAction(url: URL, request: Request, fixtures: DemoFixtures): Response {
  const pathname = url.pathname.replace('/api/v1/photos/', '');
  const [photoIdPart, action] = pathname.split('/');
  const photoId = Number(photoIdPart);
  const targetPhoto = fixtures.photos.find((photo) => photo.id === photoId);

  if (action === 'like') {
    if (!targetPhoto) {
      return new Response(JSON.stringify({ error: { message: 'Foto nicht gefunden' } }), { status: 404, headers: demoHeaders() });
    }
    const current = likeState.get(photoId) ?? targetPhoto.likes_count;
    const next = current + 1;
    likeState.set(photoId, next);
    return jsonResponse({ likes_count: next });
  }

  if (action === 'share' && request.method.toUpperCase() === 'POST') {
    return jsonResponse({ slug: fixtures.share.slug, url: `${window.location.origin}/share/${fixtures.share.slug}` });
  }

  return new Response(JSON.stringify({ error: { message: 'Demo-Endpunkt nicht verfügbar.' } }), {
    status: 404,
    headers: demoHeaders(),
  });
}

function jsonResponse(data: unknown, options: { etag?: string } = {}): Response {
  const headers = demoHeaders();
  if (options.etag) {
    headers.ETag = options.etag;
  }
  return new Response(JSON.stringify(data), {
    status: 200,
    headers,
  });
}

function demoHeaders(): Record<string, string> {
  return {
    'Content-Type': 'application/json',
    'Cache-Control': 'no-store',
  };
}

function blockedResponse(message: string): Response {
  return new Response(
    JSON.stringify({
      error: {
        code: 'demo_read_only',
        message,
      },
    }),
    {
      status: 403,
      headers: demoHeaders(),
    }
  );
}

export function isGuestDemoModeEnabled(): boolean {
  return enabled;
}

function notifyDemoToast(): void {
  if (typeof document === 'undefined') {
    return;
  }
  try {
    const detail = { type: 'info', text: 'Demo-Modus aktiv. Änderungen werden nicht gespeichert.' };
    window.setTimeout(() => {
      window.dispatchEvent(new CustomEvent('guest-toast', { detail }));
    }, 0);
  } catch {
    // ignore
  }
}
