import React, { useState, useEffect, useRef } from 'react';
import { usePlatform } from '../platform';
import { AllEmojis } from '../assets/emojis';

export function formatTime(ts) {
  const d = new Date(ts);
  const now = new Date();
  const isToday = d.toDateString() === now.toDateString();
  if (isToday) return d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
  return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
}

export function escapeHtml(str) {
  if (!str) return '';
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

export function linkifyHtml(html) {
  if (!html) return '';
  return html.replace(/(https?:\/\/[^\s<]+)/g, '<a href="$1" class="search-result-link">$1</a>');
}

export function formatEmojisHtml(html, customEmojis = []) {
  if (!html) return '';
  return html.replace(/:([a-zA-Z0-9_]+):/g, (match, name) => {
    const custom = customEmojis.find(e => e.name === name);
    if (custom) return `<img src="${custom.src}" alt="${match}" style="width:48px;height:48px;vertical-align:bottom;margin:0 1px;display:inline" />`;
    const emoji = AllEmojis.find(e => e.name === name);
    if (emoji) return `<img src="${emoji.src}" alt="${match}" style="width:48px;height:48px;vertical-align:bottom;margin:0 1px;display:inline" />`;
    return match;
  });
}

export function getAvatarColor(name) {
  const colors = ['#5865F2', '#57F287', '#FEE75C', '#EB459E', '#ED4245', '#F47B67', '#E67E22', '#3498DB'];
  let hash = 0;
  for (let i = 0; i < (name || '').length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash);
  return colors[Math.abs(hash) % colors.length];
}

export const CONVEX_PUBLIC_URL = 'https://api.brycord.com';
export const rewriteStorageUrl = (url) => {
  try {
    const u = new URL(url);
    const pub = new URL(CONVEX_PUBLIC_URL);
    u.hostname = pub.hostname;
    u.port = pub.port;
    u.protocol = pub.protocol;
    return u.toString();
  } catch { return url; }
};

export const toHexString = (bytes) =>
  bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');

export const searchImageCache = new Map();

export const SearchResultImage = ({ metadata }) => {
  const { crypto } = usePlatform();
  const fetchUrl = rewriteStorageUrl(metadata.url);
  const [url, setUrl] = useState(searchImageCache.get(fetchUrl) || null);
  const [loading, setLoading] = useState(!searchImageCache.has(fetchUrl));
  const [error, setError] = useState(null);

  useEffect(() => {
    if (searchImageCache.has(fetchUrl)) {
      setUrl(searchImageCache.get(fetchUrl));
      setLoading(false);
      return;
    }
    let isMounted = true;
    const decrypt = async () => {
      try {
        const res = await fetch(fetchUrl);
        const blob = await res.blob();
        const arrayBuffer = await blob.arrayBuffer();
        const hexInput = toHexString(new Uint8Array(arrayBuffer));
        if (hexInput.length < 32) throw new Error('Invalid file data');
        const TAG_HEX_LEN = 32;
        const contentHex = hexInput.slice(0, -TAG_HEX_LEN);
        const tagHex = hexInput.slice(-TAG_HEX_LEN);
        const decrypted = await crypto.decryptData(contentHex, metadata.key, metadata.iv, tagHex, { encoding: 'buffer' });
        const decryptedBlob = new Blob([decrypted], { type: metadata.mimeType });
        const objectUrl = URL.createObjectURL(decryptedBlob);
        if (isMounted) {
          searchImageCache.set(fetchUrl, objectUrl);
          setUrl(objectUrl);
          setLoading(false);
        }
      } catch (err) {
        console.error('Search image decrypt error:', err);
        if (isMounted) { setError('Failed to load'); setLoading(false); }
      }
    };
    decrypt();
    return () => { isMounted = false; };
  }, [fetchUrl, metadata, crypto]);

  if (loading) return <div style={{ color: 'var(--header-secondary)', fontSize: '11px', marginTop: 4 }}>Loading image...</div>;
  if (error) return null;
  return <img src={url} alt={metadata.filename} style={{ width: '100%', height: 'auto', borderRadius: 4, marginTop: 4, display: 'block' }} />;
};

export const SearchResultVideo = ({ metadata }) => {
  const { crypto } = usePlatform();
  const fetchUrl = rewriteStorageUrl(metadata.url);
  const [url, setUrl] = useState(searchImageCache.get(fetchUrl) || null);
  const [loading, setLoading] = useState(!searchImageCache.has(fetchUrl));
  const [error, setError] = useState(null);
  const [showControls, setShowControls] = useState(false);
  const videoRef = useRef(null);

  useEffect(() => {
    if (searchImageCache.has(fetchUrl)) {
      setUrl(searchImageCache.get(fetchUrl));
      setLoading(false);
      return;
    }
    let isMounted = true;
    const decrypt = async () => {
      try {
        const res = await fetch(fetchUrl);
        const blob = await res.blob();
        const arrayBuffer = await blob.arrayBuffer();
        const hexInput = toHexString(new Uint8Array(arrayBuffer));
        if (hexInput.length < 32) throw new Error('Invalid file data');
        const TAG_HEX_LEN = 32;
        const contentHex = hexInput.slice(0, -TAG_HEX_LEN);
        const tagHex = hexInput.slice(-TAG_HEX_LEN);
        const decrypted = await crypto.decryptData(contentHex, metadata.key, metadata.iv, tagHex, { encoding: 'buffer' });
        const decryptedBlob = new Blob([decrypted], { type: metadata.mimeType });
        const objectUrl = URL.createObjectURL(decryptedBlob);
        if (isMounted) {
          searchImageCache.set(fetchUrl, objectUrl);
          setUrl(objectUrl);
          setLoading(false);
        }
      } catch (err) {
        console.error('Search video decrypt error:', err);
        if (isMounted) { setError('Failed to load'); setLoading(false); }
      }
    };
    decrypt();
    return () => { isMounted = false; };
  }, [fetchUrl, metadata, crypto]);

  if (loading) return <div style={{ color: 'var(--header-secondary)', fontSize: '11px', marginTop: 4 }}>Loading video...</div>;
  if (error) return null;

  const handlePlayClick = () => { setShowControls(true); if (videoRef.current) videoRef.current.play(); };
  return (
    <div style={{ marginTop: 4, position: 'relative', display: 'inline-block', maxWidth: '100%' }}>
      <video ref={videoRef} src={url} controls={showControls} style={{ width: '100%', maxHeight: 200, borderRadius: 4, display: 'block', backgroundColor: 'black' }} />
      {!showControls && <div className="play-icon" onClick={handlePlayClick} style={{ cursor: 'pointer' }}>&#9654;</div>}
    </div>
  );
};

export const SearchResultFile = ({ metadata }) => {
  const { crypto } = usePlatform();
  const fetchUrl = rewriteStorageUrl(metadata.url);
  const [url, setUrl] = useState(searchImageCache.get(fetchUrl) || null);
  const [loading, setLoading] = useState(!searchImageCache.has(fetchUrl));

  useEffect(() => {
    if (searchImageCache.has(fetchUrl)) {
      setUrl(searchImageCache.get(fetchUrl));
      setLoading(false);
      return;
    }
    let isMounted = true;
    const decrypt = async () => {
      try {
        const res = await fetch(fetchUrl);
        const blob = await res.blob();
        const arrayBuffer = await blob.arrayBuffer();
        const hexInput = toHexString(new Uint8Array(arrayBuffer));
        if (hexInput.length < 32) return;
        const TAG_HEX_LEN = 32;
        const contentHex = hexInput.slice(0, -TAG_HEX_LEN);
        const tagHex = hexInput.slice(-TAG_HEX_LEN);
        const decrypted = await crypto.decryptData(contentHex, metadata.key, metadata.iv, tagHex, { encoding: 'buffer' });
        const decryptedBlob = new Blob([decrypted], { type: metadata.mimeType });
        const objectUrl = URL.createObjectURL(decryptedBlob);
        if (isMounted) {
          searchImageCache.set(fetchUrl, objectUrl);
          setUrl(objectUrl);
          setLoading(false);
        }
      } catch (err) {
        console.error('Search file decrypt error:', err);
        if (isMounted) setLoading(false);
      }
    };
    decrypt();
    return () => { isMounted = false; };
  }, [fetchUrl, metadata, crypto]);

  const sizeStr = metadata.size ? `${(metadata.size / 1024).toFixed(1)} KB` : '';

  return (
    <div style={{ display: 'flex', alignItems: 'center', backgroundColor: 'var(--embed-background)', padding: '8px 10px', borderRadius: 4, marginTop: 4, maxWidth: '100%' }}>
      <span style={{ marginRight: 8, fontSize: 20 }}>&#128196;</span>
      <div style={{ overflow: 'hidden', flex: 1 }}>
        <div style={{ color: 'var(--text-link)', fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', fontSize: 13 }}>{metadata.filename}</div>
        {sizeStr && <div style={{ color: 'var(--header-secondary)', fontSize: 11 }}>{sizeStr}</div>}
        {url && <a href={url} download={metadata.filename} onClick={e => e.stopPropagation()} style={{ color: 'var(--header-secondary)', fontSize: 11, textDecoration: 'underline' }}>Download</a>}
        {loading && <div style={{ color: 'var(--header-secondary)', fontSize: 11 }}>Decrypting...</div>}
      </div>
    </div>
  );
};
