import React, { useMemo, useState } from 'react';
import { Copy, Clock, Image as ImageIcon, LineChart, Code, History, GitCompare, Braces } from 'lucide-react';
import { ChartsDock } from './ChartsDock';
import { MQTTMessage } from '../types';

interface TopicDetailsProps {
  topic: string;
  lastMessage: MQTTMessage | null;
  previousMessage: MQTTMessage | null;
  maxPayloadBytes: number;
  isRecent: boolean;
  chartTopic: string | null;
  chartSeries: { times: number[]; values: number[] } | null;
  chartFields: { path: string; label: string }[];
  chartField: string;
  onChartFieldChange: (path: string) => void;
  chartSource: 'live' | 'db';
  onChartSourceChange: (source: 'live' | 'db') => void;
}

type ViewMode = 'pretty' | 'raw' | 'tree' | 'diff';

const isJSON = (value: string) => {
  try {
    JSON.parse(value);
    return true;
  } catch {
    return false;
  }
};

const isImagePayload = (payload: string) => {
  return payload.startsWith('data:image/') || (payload.length > 200 && /^[A-Za-z0-9+/=]+$/.test(payload));
};

const toImageDataUrl = (payload: string) => {
  if (payload.startsWith('data:image/')) return payload;
  return `data:image/jpeg;base64,${payload}`;
};

const sanitizeJSON = (value: unknown): { sanitized: unknown; imageDataUrl?: string } => {
  if (typeof value === 'string') {
    if (isImagePayload(value)) {
      return { sanitized: '<image>', imageDataUrl: toImageDataUrl(value) };
    }
    return { sanitized: value };
  }

  if (Array.isArray(value)) {
    let imageDataUrl: string | undefined;
    const sanitized = value.map((entry) => {
      const result = sanitizeJSON(entry);
      if (!imageDataUrl && result.imageDataUrl) {
        imageDataUrl = result.imageDataUrl;
      }
      return result.sanitized;
    });
    return { sanitized, imageDataUrl };
  }

  if (value && typeof value === 'object') {
    let imageDataUrl: string | undefined;
    const sanitized: Record<string, unknown> = {};
    Object.entries(value as Record<string, unknown>).forEach(([key, entry]) => {
      const result = sanitizeJSON(entry);
      if (!imageDataUrl && result.imageDataUrl) {
        imageDataUrl = result.imageDataUrl;
      }
      sanitized[key] = result.sanitized;
    });
    return { sanitized, imageDataUrl };
  }

  return { sanitized: value };
};

const copyWithFallback = async (text: string) => {
  if (navigator.clipboard && navigator.clipboard.writeText) {
    await navigator.clipboard.writeText(text);
    return true;
  }
  const textarea = document.createElement('textarea');
  textarea.value = text;
  textarea.setAttribute('readonly', 'true');
  textarea.style.position = 'fixed';
  textarea.style.opacity = '0';
  document.body.appendChild(textarea);
  textarea.select();
  const ok = document.execCommand('copy');
  document.body.removeChild(textarea);
  return ok;
};

const JsonTree: React.FC<{ value: unknown; depth?: number }> = ({ value, depth = 0 }) => {
  if (value === null) {
    return <span className="text-[color:var(--json-null)]">null</span>;
  }

  if (Array.isArray(value)) {
    return (
      <div className="pl-4 border-l border-[color:var(--tree-guide)]">
        {value.map((entry, idx) => (
          <div key={idx} className="flex gap-2">
            <span className="text-[color:var(--text-muted)]">[{idx}]</span>
            <JsonTree value={entry} depth={depth + 1} />
          </div>
        ))}
      </div>
    );
  }

  if (typeof value === 'object') {
    return (
      <div className="pl-4 border-l border-[color:var(--tree-guide)]">
        {Object.entries(value).map(([key, entry]) => (
          <div key={key} className="flex gap-2">
            <span className="text-[color:var(--json-key)]">{key}</span>
            <JsonTree value={entry} depth={depth + 1} />
          </div>
        ))}
      </div>
    );
  }

  if (typeof value === 'number') {
    return <span className="text-[color:var(--json-number)]">{value}</span>;
  }

  if (typeof value === 'boolean') {
    return <span className="text-[color:var(--json-boolean)]">{value ? 'true' : 'false'}</span>;
  }

  return <span className="text-[color:var(--json-string)]">"{String(value)}"</span>;
};

export const TopicDetails: React.FC<TopicDetailsProps> = ({
  topic,
  lastMessage,
  previousMessage,
  maxPayloadBytes,
  isRecent,
  chartTopic,
  chartSeries,
  chartFields,
  chartField,
  onChartFieldChange,
  chartSource,
  onChartSourceChange
}) => {
  const [viewMode, setViewMode] = useState<ViewMode>('pretty');
  const [showImage, setShowImage] = useState(false);

  const payloadPreview = useMemo(() => {
    if (!lastMessage) return '';
    if (lastMessage.payload.length <= maxPayloadBytes) return lastMessage.payload;
    return `${lastMessage.payload.slice(0, maxPayloadBytes)}...`;
  }, [lastMessage, maxPayloadBytes]);

  if (!lastMessage) {
    return (
      <div className="flex-1 flex items-center justify-center text-[color:var(--text-muted)] bg-[color:var(--bg-main)] topic-font">
        Sélectionnez un topic pour voir les détails
      </div>
    );
  }

  const payloadIsJSON = isJSON(lastMessage.payload);
  const payloadIsImage = isImagePayload(lastMessage.payload);

  const parsedJSON = payloadIsJSON ? JSON.parse(lastMessage.payload) : null;
  const parsedPreviousJSON = previousMessage && isJSON(previousMessage.payload)
    ? JSON.parse(previousMessage.payload)
    : null;
  const sanitized = payloadIsJSON ? sanitizeJSON(parsedJSON) : null;
  const imageDataUrl = sanitized?.imageDataUrl || (payloadIsImage ? toImageDataUrl(lastMessage.payload) : undefined);

  return (
    <div className="flex-1 flex flex-col bg-[color:var(--bg-main)] overflow-hidden">
      <div className={`p-4 border-b border-[color:var(--border)] flex justify-between items-center bg-[color:var(--bg-panel)] ${isRecent ? 'flash-topic' : ''}`}>
        <div className="flex flex-col min-w-0">
          <h2 className="text-sm font-mono text-[color:var(--accent-blue)] whitespace-normal break-all">{topic}</h2>
          <div className="flex items-center gap-3 mt-1 text-[10px] opacity-70">
            <span className="flex items-center gap-1"><Clock size={12}/> {new Date(lastMessage.timestamp).toLocaleTimeString()}</span>
            <span>QoS: {lastMessage.qos}</span>
            {lastMessage.retained && <span className="text-[color:var(--accent-purple)] font-bold">RETAINED</span>}
            <span>Size: {lastMessage.size} B</span>
          </div>
        </div>
        <div className="flex gap-2 items-center">
          <span className="text-[10px] opacity-50">Topic</span>
          <button
            className="p-1.5 hover:bg-[color:var(--hover-bg)] rounded flex items-center gap-1 text-[10px]"
            title="Copier le topic"
            onClick={() => {
              void copyWithFallback(topic);
            }}
          >
            <Copy size={14}/>
          </button>
        </div>
      </div>

      <div className="flex border-b border-[color:var(--border)] px-4 py-1 text-xs gap-4 bg-[color:var(--bg-panel)]/70">
        <button
          onClick={() => setViewMode('pretty')}
          className={`py-2 border-b-2 transition-all flex items-center gap-1 ${viewMode === 'pretty' ? 'border-[color:var(--accent-green)] text-[color:var(--accent-green)]' : 'border-transparent opacity-60'}`}
        >
          <Code size={12}/> Pretty JSON
        </button>
        <button
          onClick={() => setViewMode('raw')}
          className={`py-2 border-b-2 transition-all flex items-center gap-1 ${viewMode === 'raw' ? 'border-[color:var(--accent-green)] text-[color:var(--accent-green)]' : 'border-transparent opacity-60'}`}
        >
          <Braces size={12}/> Raw
        </button>
        <button
          onClick={() => setViewMode('tree')}
          className={`py-2 border-b-2 transition-all flex items-center gap-1 ${viewMode === 'tree' ? 'border-[color:var(--accent-green)] text-[color:var(--accent-green)]' : 'border-transparent opacity-60'}`}
        >
          <LineChart size={12}/> JSON Tree
        </button>
        <button
          onClick={() => setViewMode('diff')}
          className={`py-2 border-b-2 transition-all flex items-center gap-1 ${viewMode === 'diff' ? 'border-[color:var(--accent-green)] text-[color:var(--accent-green)]' : 'border-transparent opacity-60'}`}
        >
          <GitCompare size={12}/> Diff
        </button>
        <div className="ml-auto flex items-center gap-3 text-[10px] opacity-70">
          <button
            className="flex items-center gap-1 px-2 py-1 rounded border border-[color:var(--border)] hover:border-[color:var(--accent-blue)]"
            title="Copier le payload"
            onClick={() => {
              void copyWithFallback(lastMessage.payload);
            }}
          >
            <Copy size={12}/> Copier payload
          </button>
          <div className="flex items-center opacity-50 italic">
            <History size={10} className="mr-1"/> Archivage actif (SQLite)
          </div>
        </div>
      </div>

      <div className="flex-1 overflow-auto p-4 custom-scrollbar">
        {imageDataUrl && (
          <div className="mb-4 bg-[color:var(--bg-code)] p-2 rounded border border-[color:var(--border)] inline-block shadow-xl">
             <div className="flex items-center gap-2 mb-2 text-xs opacity-70 font-mono text-[color:var(--accent-purple)]"><ImageIcon size={14}/> DETECTION IMAGE BASE64</div>
             <img
               src={imageDataUrl}
               alt="MQTT Payload"
               className="max-h-[300px] object-contain rounded cursor-zoom-in"
               onClick={() => setShowImage(true)}
             />
          </div>
        )}

        {showImage && (
          <div
            className="fixed inset-0 bg-black/70 z-50 flex items-center justify-center p-6"
            onClick={() => setShowImage(false)}
          >
            <div
              className="max-w-5xl max-h-[80vh] bg-[color:var(--bg-panel)] border border-[color:var(--border)] p-4 rounded shadow-xl"
              onClick={(event) => event.stopPropagation()}
            >
              {imageDataUrl && <img src={imageDataUrl} alt="MQTT Payload" className="max-h-[70vh] object-contain" />}
            </div>
          </div>
        )}

        {viewMode === 'pretty' && (
          <div className={`bg-[color:var(--bg-code)] p-4 rounded border border-[color:var(--border)] shadow-inner ${isRecent ? 'flash-topic' : ''}`}>
            {payloadIsJSON ? (
              <pre className="font-mono payload-font text-[color:var(--json-string)] whitespace-pre-wrap">
                {JSON.stringify(sanitized?.sanitized ?? parsedJSON, null, 2)}
              </pre>
            ) : (
              <pre className="font-mono payload-font text-[color:var(--text-main)] break-all whitespace-pre-wrap">
                {payloadPreview}
              </pre>
            )}
          </div>
        )}

        {viewMode === 'raw' && (
          <div className={`bg-[color:var(--bg-code)] p-4 rounded border border-[color:var(--border)] shadow-inner ${isRecent ? 'flash-topic' : ''}`}>
            <pre className="font-mono payload-font text-[color:var(--text-main)] break-all whitespace-pre-wrap">
              {payloadPreview}
            </pre>
          </div>
        )}

        {viewMode === 'tree' && (
          <div className="bg-[color:var(--bg-code)] p-4 rounded border border-[color:var(--border)] shadow-inner text-xs">
            {payloadIsJSON ? <JsonTree value={sanitized?.sanitized ?? parsedJSON} /> : 'Payload non JSON.'}
          </div>
        )}

        {viewMode === 'diff' && (
          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div className="bg-[color:var(--bg-code)] p-4 rounded border border-[color:var(--border)] shadow-inner">
              <div className="text-[10px] uppercase tracking-widest opacity-50 mb-2">Précédent</div>
              <pre className="font-mono payload-font whitespace-pre-wrap">
                {previousMessage ? previousMessage.payload : 'Aucun message précédent.'}
              </pre>
            </div>
            <div className="bg-[color:var(--bg-code)] p-4 rounded border border-[color:var(--border)] shadow-inner">
              <div className="text-[10px] uppercase tracking-widest opacity-50 mb-2">Dernier</div>
              <pre className="font-mono payload-font whitespace-pre-wrap">
                {payloadPreview}
              </pre>
            </div>
            {payloadIsJSON && parsedPreviousJSON && (
              <div className="md:col-span-2 bg-[color:var(--bg-code)] p-4 rounded border border-[color:var(--border)] shadow-inner">
                <div className="text-[10px] uppercase tracking-widest opacity-50 mb-2">Diff JSON (référence)</div>
                <div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-xs">
                  <div>
                    <div className="text-[10px] uppercase tracking-widest opacity-40 mb-2">Avant</div>
                    <pre className="font-mono payload-font whitespace-pre-wrap">{JSON.stringify(parsedPreviousJSON, null, 2)}</pre>
                  </div>
                  <div>
                    <div className="text-[10px] uppercase tracking-widest opacity-40 mb-2">Après</div>
                    <pre className="font-mono payload-font whitespace-pre-wrap">{JSON.stringify(sanitized?.sanitized ?? parsedJSON, null, 2)}</pre>
                  </div>
                </div>
              </div>
            )}
          </div>
        )}
      </div>

      <ChartsDock
        topic={chartTopic}
        series={chartSeries}
        fields={chartFields}
        selectedField={chartField}
        onFieldChange={onChartFieldChange}
        source={chartSource}
        onSourceChange={onChartSourceChange}
      />
    </div>
  );
};
