import React, { useCallback, useEffect, useState } from 'react';
import {
  Box,
  Button,
  Header,
  Icon,
  IconButton,
  Icons,
  Scroll,
  Spinner,
  Text,
  Tooltip,
  TooltipProvider,
  config,
} from 'folds';
import { EventType, MsgType, Room } from 'matrix-js-sdk';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { mxcUrlToHttp } from '../../utils/matrix';
import { ContainerColor } from '../../styles/ContainerColor.css';

type GalleryTab = 'image' | 'video' | 'file';

type MediaGalleryProps = {
  room: Room;
  onClose: () => void;
};

const TAB_LABELS: Record<GalleryTab, string> = {
  image: 'Images',
  video: 'Videos',
  file: 'Files',
};

const TAB_MSGTYPES: Record<GalleryTab, MsgType> = {
  image: MsgType.Image,
  video: MsgType.Video,
  file: MsgType.File,
};

function TabButton({
  label,
  active,
  onClick,
}: {
  label: string;
  active: boolean;
  onClick: () => void;
}) {
  return (
    <Button
      size="300"
      variant={active ? 'Primary' : 'Secondary'}
      fill={active ? 'Soft' : 'None'}
      radii="300"
      onClick={onClick}
    >
      <Text size="B300">{label}</Text>
    </Button>
  );
}

export function MediaGallery({ room, onClose }: MediaGalleryProps) {
  const mx = useMatrixClient();
  const useAuthentication = useMediaAuthentication();

  const [tab, setTab] = useState<GalleryTab>('image');
  const [loading, setLoading] = useState(false);
  const [canLoadMore, setCanLoadMore] = useState(true);

  const msgtype = TAB_MSGTYPES[tab];

  // Read already-decrypted events from the live timeline (works for E2EE rooms)
  const getFilteredEvents = useCallback(() => {
    const timeline = room.getLiveTimeline();
    return timeline
      .getEvents()
      .filter((ev) => {
        if (ev.isRedacted()) return false;
        const content = ev.getContent();
        return ev.getType() === EventType.RoomMessage && content.msgtype === msgtype;
      })
      .slice()
      .reverse(); // newest first
  }, [room, msgtype]);

  const [events, setEvents] = useState(() => getFilteredEvents());

  useEffect(() => {
    setEvents(getFilteredEvents());
    setCanLoadMore(true);
  }, [getFilteredEvents]);

  const handleLoadMore = useCallback(async () => {
    setLoading(true);
    try {
      const timeline = room.getLiveTimeline();
      const hasMore = await mx.paginateEventTimeline(timeline, { backwards: true, limit: 100 });
      setEvents(getFilteredEvents());
      setCanLoadMore(hasMore);
    } catch {
      // silently swallow
    } finally {
      setLoading(false);
    }
  }, [mx, room, getFilteredEvents]);

  return (
    <Box
      className={ContainerColor({ variant: 'Surface' })}
      direction="Column"
      style={{
        position: 'fixed',
        top: 0,
        right: 0,
        bottom: 0,
        width: '320px',
        zIndex: 500,
        background: 'var(--bg-surface)',
        overflow: 'hidden',
      }}
    >
      {/* Header */}
      <Header
        variant="Background"
        size="600"
        style={{
          flexShrink: 0,
          padding: `0 ${config.space.S200} 0 ${config.space.S300}`,
          borderBottomWidth: config.borderWidth.B300,
        }}
      >
        <Box grow="Yes" alignItems="Center" gap="200">
          <Box grow="Yes" alignItems="Center" gap="200">
            <Icon size="200" src={Icons.Photo} />
            <Text size="H5" truncate>
              Media
            </Text>
          </Box>
          <Box shrink="No" alignItems="Center">
            <TooltipProvider
              position="Bottom"
              align="End"
              offset={4}
              tooltip={
                <Tooltip>
                  <Text>Close</Text>
                </Tooltip>
              }
            >
              {(triggerRef) => (
                <IconButton
                  ref={triggerRef}
                  variant="Background"
                  aria-label="Close media gallery"
                  onClick={onClose}
                >
                  <Icon src={Icons.Cross} />
                </IconButton>
              )}
            </TooltipProvider>
          </Box>
        </Box>
      </Header>

      {/* Tab bar */}
      <Box
        shrink="No"
        gap="100"
        style={{
          padding: config.space.S200,
        }}
      >
        {(Object.keys(TAB_LABELS) as GalleryTab[]).map((t) => (
          <TabButton key={t} label={TAB_LABELS[t]} active={tab === t} onClick={() => setTab(t)} />
        ))}
      </Box>

      {/* Content */}
      <Box
        grow="Yes"
        style={{
          position: 'relative',
          overflow: 'hidden',
        }}
      >
        <Scroll variant="Background" size="300" visibility="Hover" hideTrack>
          <Box direction="Column" gap="200" style={{ padding: config.space.S200 }}>
            {loading && events.length === 0 && (
              <Box justifyContent="Center" style={{ padding: config.space.S400 }}>
                <Spinner />
              </Box>
            )}

            {!loading && events.length === 0 && (
              <Box justifyContent="Center" style={{ padding: config.space.S400 }}>
                <Text size="T300" priority="300" align="Center">
                  {`No ${TAB_LABELS[tab].toLowerCase()} found in this room.`}
                </Text>
              </Box>
            )}

            {/* Image/Video grid */}
            {(tab === 'image' || tab === 'video') && events.length > 0 && (
              <div
                style={{
                  display: 'grid',
                  gridTemplateColumns: 'repeat(3, 1fr)',
                  gap: config.space.S100,
                }}
              >
                {events.map((mEvent) => {
                  const content = mEvent.getContent();
                  const isEncrypted = !!content.file;
                  const mxcUrl: string | undefined = content.url ?? content.file?.url;
                  if (!mxcUrl) return null;
                  const body: string = content.body ?? '';
                  // Use unauthenticated thumbnail URL — the v1 authenticated endpoint adds
                  // allow_redirect=true which Synapse rejects with 400.
                  const thumbUrl = isEncrypted
                    ? null
                    : (mxcUrlToHttp(mx, mxcUrl, false, 120, 120, 'crop') ?? null);
                  const fullUrl = mxcUrlToHttp(mx, mxcUrl, useAuthentication) ?? '#';
                  return (
                    <a
                      key={mEvent.getId()}
                      href={isEncrypted ? '#' : fullUrl}
                      target={isEncrypted ? undefined : '_blank'}
                      rel="noreferrer"
                      style={{
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'center',
                        aspectRatio: '1',
                        overflow: 'hidden',
                        borderRadius: config.radii.R300,
                        background: 'var(--bg-surface-low)',
                        cursor: isEncrypted ? 'default' : 'pointer',
                      }}
                      title={body}
                    >
                      {thumbUrl ? (
                        <img
                          src={thumbUrl}
                          alt={body}
                          onError={(e) => {
                            (e.currentTarget as HTMLImageElement).style.display = 'none';
                          }}
                          style={{
                            width: '100%',
                            height: '100%',
                            objectFit: 'cover',
                            display: 'block',
                          }}
                        />
                      ) : (
                        <Box
                          direction="Column"
                          alignItems="Center"
                          gap="100"
                          style={{ padding: config.space.S100 }}
                        >
                          <Icon src={isEncrypted ? Icons.Lock : Icons.Photo} size="400" />
                          <Text
                            size="T200"
                            truncate
                            style={{ maxWidth: '100%', textAlign: 'center', opacity: 0.7 }}
                          >
                            {body || (isEncrypted ? 'Encrypted' : 'Image')}
                          </Text>
                        </Box>
                      )}
                    </a>
                  );
                })}
              </div>
            )}

            {/* File list */}
            {tab === 'file' && events.length > 0 && (
              <Box direction="Column" gap="100">
                {events.map((mEvent) => {
                  const content = mEvent.getContent();
                  const mxcUrl: string | undefined = content.url ?? content.file?.url;
                  const body: string = content.body ?? 'Unnamed file';
                  const downloadUrl = mxcUrl
                    ? (mxcUrlToHttp(mx, mxcUrl, useAuthentication) ?? '#')
                    : '#';
                  return (
                    <Box
                      key={mEvent.getId()}
                      alignItems="Center"
                      gap="200"
                      style={{
                        padding: `${config.space.S100} ${config.space.S200}`,
                        borderRadius: config.radii.R300,
                        background: 'var(--bg-surface)',
                        overflow: 'hidden',
                      }}
                    >
                      <Icon size="200" src={Icons.File} />
                      <Box grow="Yes" style={{ overflow: 'hidden' }}>
                        <Text size="T300" truncate title={body}>
                          {body}
                        </Text>
                      </Box>
                      <IconButton
                        variant="Background"
                        size="300"
                        radii="300"
                        aria-label={`Download ${body}`}
                        onClick={() => {
                          const anchor = document.createElement('a');
                          anchor.href = downloadUrl;
                          anchor.download = body;
                          anchor.target = '_blank';
                          anchor.rel = 'noreferrer';
                          anchor.click();
                        }}
                      >
                        <Icon size="200" src={Icons.Download} />
                      </IconButton>
                    </Box>
                  );
                })}
              </Box>
            )}

            {/* Load more */}
            {canLoadMore && !loading && events.length > 0 && (
              <Box justifyContent="Center" style={{ padding: config.space.S200 }}>
                <Button
                  size="300"
                  variant="Secondary"
                  fill="Soft"
                  radii="300"
                  onClick={handleLoadMore}
                >
                  <Text size="B300">Load more</Text>
                </Button>
              </Box>
            )}

            {/* Loading more spinner */}
            {loading && events.length > 0 && (
              <Box justifyContent="Center" style={{ padding: config.space.S200 }}>
                <Spinner />
              </Box>
            )}
          </Box>
        </Scroll>
      </Box>
    </Box>
  );
}
