import React, { MouseEvent, useCallback, useEffect, useRef, useState } from 'react';
import { IPreviewUrlResponse } from 'matrix-js-sdk';
import { Box, IconButton, Scroll, Spinner, Text, as, color, config } from 'folds';
import { Icon, Icons } from '../icons';
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { UrlPreview, UrlPreviewContent, UrlPreviewDescription, UrlPreviewImg } from './UrlPreview';
import {
  getIntersectionObserverEntry,
  useIntersectionObserver,
} from '../../hooks/useIntersectionObserver';
import * as css from './UrlPreviewCard.css';
import { tryDecodeURIComponent } from '../../utils/dom';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { useAuthenticatedMediaUrl } from '../../hooks/useAuthenticatedMediaUrl';
import { openExternalUrl } from '../../utils/tauri';

const linkStyles = { color: color.Success.Main };

/**
 * Click handler for external links - uses Tauri shell on desktop/mobile
 */
const handleExternalLinkClick = (e: MouseEvent<HTMLAnchorElement>) => {
  const href = e.currentTarget.href;
  if (href && (href.startsWith('http://') || href.startsWith('https://'))) {
    e.preventDefault();
    openExternalUrl(href);
  }
};

/**
 * Preview image component with authentication support
 */
const AuthenticatedUrlPreviewImg = ({
  src,
  useAuthentication,
  ...props
}: React.ComponentProps<typeof UrlPreviewImg> & { useAuthentication: boolean }) => {
  const authenticatedSrc = useAuthenticatedMediaUrl(src, useAuthentication);
  return <UrlPreviewImg src={authenticatedSrc} {...props} />;
};

export const UrlPreviewCard = as<'div', { url: string; ts: number }>(
  ({ url, ts, ...props }, ref) => {
    const mx = useMatrixClient();
    const useAuthentication = useMediaAuthentication();
    const [previewStatus, loadPreview] = useAsyncCallback(
      useCallback(() => mx.getUrlPreview(url, ts), [url, ts, mx])
    );

    useEffect(() => {
      loadPreview().catch((error) => {
        // Log preview errors for debugging - common causes:
        // - 502/503: Matrix server's URL preview service is down/misconfigured
        // - 404: URL preview endpoint not available on this server
        // - Network errors: connectivity issues
        if (error?.httpStatus === 502 || error?.httpStatus === 503) {
          // Server's URL preview backend is down - this is a server-side issue
          // eslint-disable-next-line no-console
          console.warn('[UrlPreview] Server URL preview service unavailable (502/503):', url);
        } else if (error?.httpStatus === 404) {
          // Server doesn't support URL previews
          // eslint-disable-next-line no-console
          console.info('[UrlPreview] Server does not support URL previews:', url);
        }
      });
    }, [loadPreview, url]);

    if (previewStatus.status === AsyncStatus.Error) return null;

    const renderContent = (prev: IPreviewUrlResponse) => {
      const ogImage = prev['og:image'] || '';
      // SVGs can't be thumbnailed by Matrix servers, load them directly
      // Also check og:image:type if available
      const isSvg =
        ogImage.toLowerCase().endsWith('.svg') ||
        prev['og:image:type'] === 'image/svg+xml';
      const imgUrl = isSvg
        ? mxcUrlToHttp(mx, ogImage, useAuthentication)
        : mxcUrlToHttp(mx, ogImage, useAuthentication, 256, 256, 'scale', false);

      return (
        <>
          {imgUrl && (
            <AuthenticatedUrlPreviewImg
              src={imgUrl}
              useAuthentication={useAuthentication}
              alt={prev['og:title']}
              title={prev['og:title']}
              style={isSvg ? { padding: '10px' } : undefined}
            />
          )}
          <UrlPreviewContent>
            <Text
              style={linkStyles}
              truncate
              as="a"
              href={url}
              target="_blank"
              rel="no-referrer"
              size="T200"
              priority="300"
              onClick={handleExternalLinkClick}
            >
              {typeof prev['og:site_name'] === 'string' && `${prev['og:site_name']} | `}
              {tryDecodeURIComponent(url)}
            </Text>
            <Text truncate priority="400">
              <b>{prev['og:title']}</b>
            </Text>
            <Text size="T200" priority="300">
              <UrlPreviewDescription>{prev['og:description']}</UrlPreviewDescription>
            </Text>
          </UrlPreviewContent>
        </>
      );
    };

    return (
      <UrlPreview {...props} ref={ref}>
        {previewStatus.status === AsyncStatus.Success ? (
          renderContent(previewStatus.data)
        ) : (
          <Box grow="Yes" alignItems="Center" justifyContent="Center">
            <Spinner variant="Secondary" size="400" />
          </Box>
        )}
      </UrlPreview>
    );
  }
);

export const UrlPreviewHolder = as<'div'>(({ children, ...props }, ref) => {
  const scrollRef = useRef<HTMLDivElement>(null);
  const backAnchorRef = useRef<HTMLDivElement>(null);
  const frontAnchorRef = useRef<HTMLDivElement>(null);
  const [backVisible, setBackVisible] = useState(true);
  const [frontVisible, setFrontVisible] = useState(true);

  const intersectionObserver = useIntersectionObserver(
    useCallback((entries) => {
      const backAnchor = backAnchorRef.current;
      const frontAnchor = frontAnchorRef.current;
      const backEntry = backAnchor && getIntersectionObserverEntry(backAnchor, entries);
      const frontEntry = frontAnchor && getIntersectionObserverEntry(frontAnchor, entries);
      if (backEntry) {
        setBackVisible(backEntry.isIntersecting);
      }
      if (frontEntry) {
        setFrontVisible(frontEntry.isIntersecting);
      }
    }, []),
    useCallback(
      () => ({
        root: scrollRef.current,
        rootMargin: '10px',
      }),
      []
    )
  );

  useEffect(() => {
    const backAnchor = backAnchorRef.current;
    const frontAnchor = frontAnchorRef.current;
    if (backAnchor) intersectionObserver?.observe(backAnchor);
    if (frontAnchor) intersectionObserver?.observe(frontAnchor);
    return () => {
      if (backAnchor) intersectionObserver?.unobserve(backAnchor);
      if (frontAnchor) intersectionObserver?.unobserve(frontAnchor);
    };
  }, [intersectionObserver]);

  const handleScrollBack = () => {
    const scroll = scrollRef.current;
    if (!scroll) return;
    const { offsetWidth, scrollLeft } = scroll;
    scroll.scrollTo({
      left: scrollLeft - offsetWidth / 1.3,
      behavior: 'smooth',
    });
  };
  const handleScrollFront = () => {
    const scroll = scrollRef.current;
    if (!scroll) return;
    const { offsetWidth, scrollLeft } = scroll;
    scroll.scrollTo({
      left: scrollLeft + offsetWidth / 1.3,
      behavior: 'smooth',
    });
  };

  return (
    <Box
      direction="Column"
      {...props}
      ref={ref}
      style={{ marginTop: config.space.S200, position: 'relative' }}
    >
      <Scroll ref={scrollRef} direction="Horizontal" size="0" visibility="Hover" hideTrack>
        <Box shrink="No" alignItems="Center">
          <div ref={backAnchorRef} />
          {!backVisible && (
            <>
              <div className={css.UrlPreviewHolderGradient({ position: 'Left' })} />
              <IconButton
                className={css.UrlPreviewHolderBtn({ position: 'Left' })}
                variant="Secondary"
                radii="Pill"
                size="300"
                outlined
                onClick={handleScrollBack}
              >
                <Icon size="300" src={Icons.ArrowLeft} />
              </IconButton>
            </>
          )}
          <Box alignItems="Inherit" gap="200">
            {children}

            {!frontVisible && (
              <>
                <div className={css.UrlPreviewHolderGradient({ position: 'Right' })} />
                <IconButton
                  className={css.UrlPreviewHolderBtn({ position: 'Right' })}
                  variant="Primary"
                  radii="Pill"
                  size="300"
                  outlined
                  onClick={handleScrollFront}
                >
                  <Icon size="300" src={Icons.ArrowRight} />
                </IconButton>
              </>
            )}
            <div ref={frontAnchorRef} />
          </Box>
        </Box>
      </Scroll>
    </Box>
  );
});
