import type { Metadata } from 'next';
import Link from 'next/link';
import { ArrowRight, LockKeyhole } from 'lucide-react';
import { prisma } from '@/lib/prisma';
import { config } from '@/lib/config';
import { getLinkAccessState } from '@/lib/link-access';
import { getServerConfig } from '@/lib/server-config';

type PreviewPageProps = {
  params: Promise<{ slug: string }>;
};

const FALLBACK_TITLE = config.projectName;
const FALLBACK_DESCRIPTION = config.description;

type SourceOgData = {
  title: string | null;
  description: string | null;
  image: string | null;
};

function decodeHtmlEntities(value: string) {
  return value
    .replace(/&amp;/gi, '&')
    .replace(/&lt;/gi, '<')
    .replace(/&gt;/gi, '>')
    .replace(/&quot;/gi, '"')
    .replace(/&#39;/gi, "'")
    .trim();
}

function escapeRegex(value: string) {
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

function extractMetaValue(html: string, metaName: string) {
  const escapedName = escapeRegex(metaName);
  const tagPattern = new RegExp(`<meta[^>]+(?:property|name|itemprop)=["']${escapedName}["'][^>]*>`, 'i');
  const tagMatch = html.match(tagPattern);

  if (!tagMatch) {
    return null;
  }

  const contentMatch = tagMatch[0].match(/content=["']([^"']+)["']/i);
  if (!contentMatch?.[1]) {
    return null;
  }

  return decodeHtmlEntities(contentMatch[1]);
}

function getSourceFallbackDescription(url: string) {
  try {
    const hostname = new URL(url).hostname;
    return `Перейти на ${hostname}`;
  } catch {
    return 'Перейти по ссылке';
  }
}

function extractTitleTag(html: string) {
  const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
  if (!titleMatch?.[1]) {
    return null;
  }

  const normalized = titleMatch[1].replace(/\s+/g, ' ').trim();
  return normalized ? decodeHtmlEntities(normalized) : null;
}

function resolveSourceImageUrl(imageUrl: string | null, pageUrl: string) {
  if (!imageUrl) {
    return null;
  }

  try {
    return new URL(imageUrl, pageUrl).toString();
  } catch {
    return null;
  }
}

async function getSourceOgData(url: string): Promise<SourceOgData> {
  const serverConfig = await getServerConfig();
  const controller = new AbortController();
  const timeout = setTimeout(() => controller.abort(), serverConfig.og.sourceFetchTimeoutMs);

  try {
    const response = await fetch(url, {
      redirect: 'follow',
      signal: controller.signal,
      headers: {
        'user-agent': 'LinkSnapOGFetcher/1.0 (+https://linksnap.local)',
        accept: 'text/html,application/xhtml+xml',
      },
      next: {
        revalidate: 1800,
      },
    });

    if (!response.ok) {
      return { title: null, description: null, image: null };
    }

    const contentType = response.headers.get('content-type') || '';
    if (!contentType.toLowerCase().includes('text/html')) {
      return { title: null, description: null, image: null };
    }

    const html = await response.text();
    const title =
      extractMetaValue(html, 'og:title') ||
      extractMetaValue(html, 'twitter:title') ||
      extractTitleTag(html);

    const description =
      extractMetaValue(html, 'og:description') ||
      extractMetaValue(html, 'twitter:description') ||
      extractMetaValue(html, 'description');

    const image = resolveSourceImageUrl(
      extractMetaValue(html, 'og:image') || extractMetaValue(html, 'twitter:image'),
      response.url || url
    );

    return { title, description, image };
  } catch {
    return { title: null, description: null, image: null };
  } finally {
    clearTimeout(timeout);
  }
}

function toAbsoluteUrl(url: string | null | undefined) {
  if (!url) {
    return null;
  }

  if (url.startsWith('http://') || url.startsWith('https://')) {
    return url;
  }

  if (!url.startsWith('/')) {
    return `${config.baseUrl}/${url}`;
  }

  return `${config.baseUrl}${url}`;
}

async function getLinkBySlug(slug: string) {
  return prisma.link.findUnique({
    where: { slug },
    select: {
      id: true,
      slug: true,
      longUrl: true,
      title: true,
      description: true,
      ogTitle: true,
      ogDescription: true,
      ogImage: true,
      isActive: true,
      expiresAt: true,
      clickLimit: true,
      clicks: true,
      passwordHash: true,
    },
  });
}

export async function generateMetadata({ params }: PreviewPageProps): Promise<Metadata> {
  const { slug } = await params;
  const link = await getLinkBySlug(slug);

  if (!link) {
    return {
      title: 'Ссылка не найдена',
      description: FALLBACK_DESCRIPTION,
      robots: { index: false, follow: false },
    };
  }

  const access = getLinkAccessState(link);
  const isUnavailable = !access.isAvailable;
  const isPasswordProtected = Boolean(link.passwordHash);

  const sourceOgData = !isUnavailable && !isPasswordProtected
    ? await getSourceOgData(link.longUrl)
    : { title: null, description: null, image: null };

  const hasSourceTitle = Boolean(sourceOgData.title);

  const title = isUnavailable || isPasswordProtected
    ? link.title || FALLBACK_TITLE
    : link.ogTitle || sourceOgData.title || link.title || FALLBACK_TITLE;

  const description = isUnavailable
    ? 'Эта ссылка недоступна.'
    : isPasswordProtected
      ? 'Эта ссылка защищена паролем.'
      : link.ogDescription
        || sourceOgData.description
        || link.description
        || (hasSourceTitle ? getSourceFallbackDescription(link.longUrl) : FALLBACK_DESCRIPTION);

  const imageUrl = isUnavailable || isPasswordProtected
    ? null
    : toAbsoluteUrl(link.ogImage) || sourceOgData.image;

  const canonicalUrl = `${config.baseUrl}/${slug}`;

  return {
    title,
    description,
    robots: { index: false, follow: true },
    alternates: { canonical: canonicalUrl },
    openGraph: {
      type: 'website',
      url: canonicalUrl,
      siteName: config.projectName,
      title,
      description,
      images: imageUrl ? [{ url: imageUrl }] : undefined,
    },
    twitter: {
      card: imageUrl ? 'summary_large_image' : 'summary',
      title,
      description,
      images: imageUrl ? [imageUrl] : undefined,
    },
  };
}

export default async function PreviewSlugPage({ params }: PreviewPageProps) {
  const { slug } = await params;
  const link = await getLinkBySlug(slug);

  if (!link) {
    return (
      <main className="flex min-h-screen items-center justify-center bg-[#050505] p-6 text-white">
        <p className="text-sm text-gray-400">Ссылка не найдена</p>
      </main>
    );
  }

  const access = getLinkAccessState(link);
  const isUnavailable = !access.isAvailable;
  const isPasswordProtected = Boolean(link.passwordHash);

  if (isUnavailable) {
    return (
      <main className="flex min-h-screen items-center justify-center bg-[#050505] p-6 text-white">
        <p className="text-sm text-gray-400">Ссылка недоступна</p>
      </main>
    );
  }

  if (isPasswordProtected) {
    return (
      <main className="flex min-h-screen items-center justify-center bg-[#050505] p-6 text-white">
        <Link
          href={`/unlock/${slug}`}
          className="inline-flex items-center gap-2 rounded-xl border border-white/10 bg-white/[0.03] px-4 py-2.5 text-sm text-gray-200 transition-colors hover:bg-white/[0.08] hover:text-white"
        >
          <LockKeyhole className="h-4 w-4 text-violet-300" />
          Перейти к разблокировке
        </Link>
      </main>
    );
  }

  return (
    <main className="flex min-h-screen items-center justify-center bg-[#050505] p-6 text-white">
      <a
        href={link.longUrl}
        className="inline-flex items-center gap-2 rounded-xl border border-white/10 bg-white/[0.03] px-4 py-2.5 text-sm text-gray-200 transition-colors hover:bg-white/[0.08] hover:text-white"
      >
        Перейти по ссылке
        <ArrowRight className="h-4 w-4 text-violet-300" />
      </a>
    </main>
  );
}
