import { Router } from 'express';
import { getKlipyApiKey, hasKlipyApiKey } from '../config/variables';

const router = Router();
const KLIPY_API_BASE_URL = 'https://api.klipy.com/api/v1';
const REQUEST_TIMEOUT_MS = 8000;
const DEFAULT_PAGE = 1;
const DEFAULT_PER_PAGE = 24;
const MAX_PER_PAGE = 50;

interface NormalizedMediaMeta {
  url: string;
  width?: number;
  height?: number;
}

interface NormalizedKlipyGif {
  id: string;
  slug: string;
  title?: string;
  url: string;
  previewUrl: string;
  width: number;
  height: number;
}

interface KlipyGifVariants {
  md?: unknown;
  sm?: unknown;
  xs?: unknown;
  hd?: unknown;
}

interface KlipyGifItem {
  type?: unknown;
  slug?: unknown;
  id?: unknown;
  title?: unknown;
  file?: KlipyGifVariants;
}

interface KlipyApiResponse {
  data?: {
    data?: unknown;
    has_next?: unknown;
  };
}

interface ResolvedGifMedia {
  previewMeta: NormalizedMediaMeta | null;
  sourceMeta: NormalizedMediaMeta;
}

function pickFirst<T>(...values: (T | null | undefined)[]): T | undefined {
  for (const value of values) {
    if (value != null)
      return value;
  }

  return undefined;
}

function sanitizeString(value: unknown): string | undefined {
  if (typeof value !== 'string')
    return undefined;

  const trimmed = value.trim();

  return trimmed || undefined;
}

function toPositiveNumber(value: unknown): number | undefined {
  const parsed = Number(value);

  return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
}

function clampPositiveInt(value: unknown, fallback: number, max = Number.MAX_SAFE_INTEGER): number {
  const parsed = Number(value);

  if (!Number.isFinite(parsed) || parsed < 1)
    return fallback;

  return Math.min(Math.floor(parsed), max);
}

function normalizeMediaMeta(candidate: unknown): NormalizedMediaMeta | null {
  if (!candidate)
    return null;

  if (typeof candidate === 'string') {
    return { url: candidate };
  }

  if (typeof candidate === 'object' && candidate !== null) {
    const url = sanitizeString((candidate as { url?: unknown }).url);

    if (!url)
      return null;

    return {
      url,
      width: toPositiveNumber((candidate as { width?: unknown }).width),
      height: toPositiveNumber((candidate as { height?: unknown }).height)
    };
  }

  return null;
}

function pickGifMeta(sizeVariant: unknown): NormalizedMediaMeta | null {
  const candidate = sizeVariant as {
    gif?: unknown;
    webp?: unknown;
  } | undefined;

  return normalizeMediaMeta(candidate?.gif) ?? normalizeMediaMeta(candidate?.webp);
}

function extractKlipyResponseData(payload: unknown): { items: unknown[]; hasNext: boolean } {
  if (typeof payload !== 'object' || payload === null) {
    return {
      items: [],
      hasNext: false
    };
  }

  const response = payload as KlipyApiResponse;
  const items = Array.isArray(response.data?.data) ? response.data.data : [];

  return {
    items,
    hasNext: response.data?.has_next === true
  };
}

function resolveGifMedia(file?: KlipyGifVariants): ResolvedGifMedia | null {
  const previewVariant = pickFirst(file?.md, file?.sm, file?.xs, file?.hd);
  const sourceVariant = pickFirst(file?.hd, file?.md, file?.sm, file?.xs);
  const previewMeta = pickGifMeta(previewVariant);
  const sourceMeta = pickGifMeta(sourceVariant) ?? previewMeta;

  if (!sourceMeta?.url)
    return null;

  return {
    previewMeta,
    sourceMeta
  };
}

function resolveGifSlug(gifItem: KlipyGifItem): string | undefined {
  return sanitizeString(gifItem.slug) ?? sanitizeString(gifItem.id);
}

function normalizeGifItem(item: unknown): NormalizedKlipyGif | null {
  if (!item || typeof item !== 'object')
    return null;

  const gifItem = item as KlipyGifItem;
  const resolvedMedia = resolveGifMedia(gifItem.file);
  const slug = resolveGifSlug(gifItem);

  if (gifItem.type === 'ad')
    return null;

  if (!slug || !resolvedMedia)
    return null;

  const { previewMeta, sourceMeta } = resolvedMedia;

  return {
    id: slug,
    slug,
    title: sanitizeString(gifItem.title),
    url: sourceMeta.url,
    previewUrl: previewMeta?.url ?? sourceMeta.url,
    width: sourceMeta.width ?? previewMeta?.width ?? 0,
    height: sourceMeta.height ?? previewMeta?.height ?? 0
  };
}

function extractErrorMessage(payload: unknown): string | null {
  if (!payload)
    return null;

  if (typeof payload === 'string')
    return payload.slice(0, 240);

  if (typeof payload === 'object' && payload !== null) {
    const data = payload as { error?: unknown; message?: unknown };

    if (typeof data.error === 'string')
      return data.error;

    if (typeof data.message === 'string')
      return data.message;
  }

  return null;
}

router.get('/klipy/config', (_req, res) => {
  res.json({ enabled: hasKlipyApiKey() });
});

router.get('/klipy/gifs', async (req, res) => {
  if (!hasKlipyApiKey()) {
    return res.status(503).json({ error: 'KLIPY is not configured on this server.' });
  }

  try {
    const query = sanitizeString(req.query.q) ?? '';
    const page = clampPositiveInt(req.query.page, DEFAULT_PAGE);
    const perPage = clampPositiveInt(req.query.per_page, DEFAULT_PER_PAGE, MAX_PER_PAGE);
    const customerId = sanitizeString(req.query.customer_id);
    const locale = sanitizeString(req.query.locale);
    const params = new URLSearchParams({
      page: String(page),
      per_page: String(perPage)
    });

    if (query)
      params.set('q', query);

    if (customerId)
      params.set('customer_id', customerId);

    if (locale)
      params.set('locale', locale);

    const endpoint = query ? 'search' : 'trending';
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
    const response = await fetch(
      `${KLIPY_API_BASE_URL}/${encodeURIComponent(getKlipyApiKey())}/gifs/${endpoint}?${params.toString()}`,
      {
        headers: { accept: 'application/json' },
        signal: controller.signal
      }
    );

    clearTimeout(timeout);

    const text = await response.text();

    let payload: unknown = null;

    if (text) {
      try {
        payload = JSON.parse(text) as unknown;
      } catch {
        payload = text;
      }
    }

    if (!response.ok) {
      return res.status(response.status).json({
        error: extractErrorMessage(payload) || 'Failed to fetch GIFs from KLIPY.'
      });
    }

    const { items: rawItems, hasNext } = extractKlipyResponseData(payload);
    const results = rawItems
      .map((item: unknown) => normalizeGifItem(item))
      .filter((item: NormalizedKlipyGif | null): item is NormalizedKlipyGif => !!item);

    res.json({
      enabled: true,
      results,
      hasNext
    });
  } catch (error) {
    if ((error as { name?: string })?.name === 'AbortError') {
      return res.status(504).json({ error: 'KLIPY request timed out.' });
    }

    console.error('KLIPY GIF route error:', error);
    res.status(502).json({ error: 'Failed to fetch GIFs from KLIPY.' });
  }
});

export default router;
