import { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';

import { useCall } from '../context/CallContext';
import { listScreenSources, type ScreenSource } from '../lib/screenSources';
import {
  type ScreenSharePreset,
  getScreenShareSettings,
  updateScreenShareSettings,
} from '../lib/screenShareSettings';
import { MonitorShareIcon } from './icons';

interface Props {
  onClose: () => void;
}

// Discord trims the picker to two questions: which source, and a couple of
// quality knobs. Anything else lives in Settings → Bildschirmfreigabe (it
// already does in this app). So the modal here mirrors that — tabs to switch
// between screens and windows, thumbnail grid, and a compact footer with
// quality + audio.

const TABS = [
  { id: 'screen' as const, label: 'Bildschirme' },
  { id: 'window' as const, label: 'Anwendungen' },
];
type TabId = (typeof TABS)[number]['id'];

// Resolution and framerate are picked independently. The preset table
// (screenShareSettings.ts) still provides the per-tier bitrate/dimension
// caps, so we map (res, fps) → existing preset and rely on
// `framerateOverride` for the non-default framerate combinations
// (e.g. 1440p · 30, 4K · 30).
type ResChoice = 'auto' | '720p' | '1080p' | '1440p' | '4k';
type FpsChoice = 30 | 60;

const RES_PILLS: { id: ResChoice; label: string }[] = [
  { id: 'auto', label: 'Auto' },
  { id: '720p', label: '720p' },
  { id: '1080p', label: '1080p' },
  { id: '1440p', label: '1440p' },
  { id: '4k', label: '4K' },
];

const FPS_PILLS: { id: FpsChoice; label: string }[] = [
  { id: 30, label: '30 fps' },
  { id: 60, label: '60 fps' },
];

function presetForResFps(res: ResChoice, fps: FpsChoice): ScreenSharePreset {
  switch (res) {
    case 'auto':
      return 'auto';
    case '720p':
      return fps === 60 ? '720p60' : '720p30';
    case '1080p':
      return fps === 60 ? '1080p60' : '1080p30';
    case '1440p':
      return '1440p60';
    case '4k':
      return '4k60';
  }
}

function decomposePreset(
  p: ScreenSharePreset,
  framerateOverride: number | null,
): { res: ResChoice; fps: FpsChoice } {
  const fallback: FpsChoice = framerateOverride === 30 ? 30 : 60;
  switch (p) {
    case 'auto':
      return { res: 'auto', fps: framerateOverride === 60 ? 60 : 30 };
    case '720p30':
      return { res: '720p', fps: 30 };
    case '720p60':
      return { res: '720p', fps: 60 };
    case '1080p30':
      return { res: '1080p', fps: 30 };
    case '1080p60':
      return { res: '1080p', fps: 60 };
    case '1440p60':
      return { res: '1440p', fps: fallback };
    case '4k60':
      return { res: '4k', fps: fallback };
  }
}

const THUMBNAIL_REFRESH_MS = 3500;

export function ScreenSharePickerModal({ onClose }: Props) {
  const { startScreenShare } = useCall();

  const [tab, setTab] = useState<TabId>('screen');
  const [sources, setSources] = useState<ScreenSource[]>([]);
  const [loading, setLoading] = useState(true);
  const [selectedId, setSelectedId] = useState<string | null>(null);

  const [res, setRes] = useState<ResChoice>(() => {
    const s = getScreenShareSettings();
    return decomposePreset(s.preset, s.framerateOverride).res;
  });
  const [fps, setFps] = useState<FpsChoice>(() => {
    const s = getScreenShareSettings();
    return decomposePreset(s.preset, s.framerateOverride).fps;
  });
  const [audio, setAudio] = useState<boolean>(
    () => getScreenShareSettings().includeSystemAudio,
  );

  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Load + refresh thumbnails. Local `cancelled` flag is the single source
  // of mount-state truth; we deliberately do NOT use a mountedRef pattern
  // because React 18 strict-mode runs effects twice and a ref set to false
  // in cleanup never gets re-set on remount, leaving `Lade …` hanging.
  useEffect(() => {
    let cancelled = false;
    let timer: ReturnType<typeof setTimeout> | null = null;

    const tick = async () => {
      try {
        const list = await listScreenSources();
        if (cancelled) return;
        setSources(list);
        setLoading(false);
      } catch (err) {
        if (cancelled) return;
        console.warn('listScreenSources failed', err);
        setLoading(false);
      }
      if (cancelled) return;
      timer = setTimeout(() => {
        if (!cancelled && !busy) void tick();
      }, THUMBNAIL_REFRESH_MS);
    };
    void tick();

    return () => {
      cancelled = true;
      if (timer) clearTimeout(timer);
    };
  }, [busy]);

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape' && !busy) {
        e.preventDefault();
        onClose();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose, busy]);

  const visibleSources = sources.filter((s) => s.kind === tab);

  const handleClose = () => {
    if (busy) return;
    void window.electronAPI.setPendingShareSource(null).catch(() => {});
    onClose();
  };

  const handleStart = async () => {
    if (!selectedId) return;
    setError(null);
    setBusy(true);
    try {
      const preset = presetForResFps(res, fps);
      // Persist resolution + fps + audio. The duck flag is force-cleared
      // because the native loopback addon now excludes the app's own audio
      // at OS level; JS-side ducking (which also muted incoming peer audio)
      // was causing "I can't hear anyone" on earlier builds.
      updateScreenShareSettings({
        preset,
        framerateOverride: fps,
        includeSystemAudio: audio,
        duckRemoteAudioWhileSharing: false,
      });
      // Stage the picked source id for main BEFORE getDisplayMedia. Main
      // reads + clears it on the next display-media request.
      await window.electronAPI.setPendingShareSource(selectedId);
      await startScreenShare({
        preset,
        displaySurface: tab === 'screen' ? 'monitor' : 'window',
        framerate: fps,
        // Forward the picked source id so the native loopback path can
        // switch into INCLUDE_TARGET_PROCESS_TREE for window-shares
        // (parses HWND from `window:<HWND>:0`). For screen-shares this
        // is just informational — the EXCLUDE-self path stays in play.
        pickedSourceId: selectedId,
      });
      onClose();
    } catch (err: unknown) {
      try {
        await window.electronAPI.setPendingShareSource(null);
      } catch {
        /* main may already be torn down */
      }
      const msg = err instanceof Error ? err.message : '';
      if (/cancel|abort|user/i.test(msg)) {
        onClose();
        return;
      }
      setError(msg || 'Bildschirm-Quelle konnte nicht geladen werden');
    } finally {
      setBusy(false);
    }
  };

  return createPortal(
    <div
      className="fixed inset-0 z-[120] flex items-center justify-center bg-black/70 p-6 backdrop-blur-sm motion-safe:animate-fade-in"
      onMouseDown={(e) => {
        if (e.target === e.currentTarget) handleClose();
      }}
    >
      <div
        role="dialog"
        aria-label="Bildschirmfreigabe"
        className="relative flex max-h-[88vh] w-full max-w-[680px] motion-safe:animate-slide-up flex-col overflow-hidden rounded-xl border border-line bg-surface-2 shadow-xl"
      >
        {/* Header */}
        <div className="flex items-center justify-between border-b border-line px-5 py-3">
          <div className="flex items-center gap-2.5">
            <MonitorShareIcon className="h-5 w-5 text-fg-muted" />
            <h2 className="text-base font-semibold text-fg">Bildschirmfreigabe</h2>
          </div>
        </div>

        {/* Tabs */}
        <div className="flex border-b border-line px-3">
          {TABS.map((t) => {
            const active = tab === t.id;
            return (
              <button
                key={t.id}
                type="button"
                onClick={() => {
                  setTab(t.id);
                  setSelectedId(null);
                }}
                className={
                  'relative cursor-pointer px-4 py-2.5 text-sm transition focus:outline-none ' +
                  (active
                    ? 'font-semibold text-fg'
                    : 'text-fg-muted hover:text-fg')
                }
              >
                {t.label}
                {active && (
                  <span className="absolute inset-x-3 -bottom-px h-0.5 rounded-full bg-accent" />
                )}
              </button>
            );
          })}
        </div>

        {/* Source grid */}
        <div className="flex-1 overflow-y-auto px-4 py-4">
          {loading && visibleSources.length === 0 ? (
            <div className="grid grid-cols-2 gap-3">
              {Array.from({ length: 4 }).map((_, i) => (
                <div
                  key={i}
                  className="aspect-video animate-pulse rounded-lg border border-line bg-surface-3"
                />
              ))}
            </div>
          ) : visibleSources.length === 0 ? (
            <div className="rounded-lg border border-dashed border-line bg-surface-3/30 px-4 py-10 text-center text-xs text-fg-muted">
              {tab === 'screen' ? 'Keine Bildschirme gefunden.' : 'Keine offenen Anwendungen.'}
            </div>
          ) : (
            <div className="grid grid-cols-2 gap-3">
              {visibleSources.map((src) => {
                const active = selectedId === src.id;
                return (
                  <button
                    key={src.id}
                    type="button"
                    onClick={() => setSelectedId(src.id)}
                    className={
                      'group flex flex-col overflow-hidden rounded-lg border text-left transition focus:outline-none ' +
                      (active
                        ? 'border-accent ring-2 ring-accent/40 bg-accent/5'
                        : 'border-line bg-surface-3 hover:border-accent/50')
                    }
                  >
                    <div className="relative aspect-video w-full overflow-hidden bg-black/40">
                      {src.thumbnailDataUrl ? (
                        <img
                          src={src.thumbnailDataUrl}
                          alt=""
                          className="h-full w-full object-contain"
                          draggable={false}
                        />
                      ) : (
                        <div className="flex h-full w-full items-center justify-center text-[10px] text-fg-muted">
                          —
                        </div>
                      )}
                    </div>
                    <div className="flex items-center gap-2 px-2.5 py-2">
                      {src.iconDataUrl && (
                        <img
                          src={src.iconDataUrl}
                          alt=""
                          className="h-4 w-4 flex-none"
                          draggable={false}
                        />
                      )}
                      <span
                        className="truncate text-xs font-medium text-fg"
                        title={src.name}
                      >
                        {src.name}
                      </span>
                    </div>
                  </button>
                );
              })}
            </div>
          )}
        </div>

        {/* Footer config */}
        <div className="border-t border-line bg-surface-3/30 px-5 py-3">
          <div className="flex flex-wrap items-center gap-x-5 gap-y-3">
            <div className="flex items-center gap-2">
              <span className="text-[11px] font-semibold uppercase tracking-wide text-fg-muted">
                Auflösung
              </span>
              <div className="flex gap-1">
                {RES_PILLS.map((q) => {
                  const active = res === q.id;
                  return (
                    <button
                      key={q.id}
                      type="button"
                      onClick={() => setRes(q.id)}
                      className={
                        'cursor-pointer rounded-md border px-2.5 py-1 text-[11px] font-medium transition focus:outline-none ' +
                        (active
                          ? 'border-accent bg-accent/10 text-fg'
                          : 'border-line bg-surface-3 text-fg-muted hover:text-fg')
                      }
                    >
                      {q.label}
                    </button>
                  );
                })}
              </div>
            </div>

            <div className="flex items-center gap-2">
              <span className="text-[11px] font-semibold uppercase tracking-wide text-fg-muted">
                FPS
              </span>
              <div className="flex gap-1">
                {FPS_PILLS.map((q) => {
                  const active = fps === q.id;
                  return (
                    <button
                      key={q.id}
                      type="button"
                      onClick={() => setFps(q.id)}
                      className={
                        'cursor-pointer rounded-md border px-2.5 py-1 text-[11px] font-medium transition focus:outline-none ' +
                        (active
                          ? 'border-accent bg-accent/10 text-fg'
                          : 'border-line bg-surface-3 text-fg-muted hover:text-fg')
                      }
                    >
                      {q.label}
                    </button>
                  );
                })}
              </div>
            </div>

            <label className="ml-auto flex cursor-pointer items-center gap-2 text-xs text-fg">
              <input
                type="checkbox"
                checked={audio}
                onChange={(e) => setAudio(e.target.checked)}
                className="h-3.5 w-3.5 cursor-pointer accent-accent"
              />
              <span>Sound mitstreamen</span>
            </label>
          </div>


          {error && (
            <p className="mt-2 rounded border border-rose-500/30 bg-rose-500/10 px-2.5 py-1.5 text-[11px] text-rose-600 dark:text-rose-300">
              {error}
            </p>
          )}
        </div>

        {/* Actions */}
        <div className="flex items-center justify-end gap-2 border-t border-line bg-surface-2 px-5 py-3">
          <button
            type="button"
            disabled={busy}
            onClick={handleClose}
            className="cursor-pointer rounded-md px-3 py-1.5 text-sm font-medium text-fg-muted transition hover:text-fg disabled:opacity-50 focus:outline-none"
          >
            Abbrechen
          </button>
          <button
            type="button"
            disabled={busy || !selectedId}
            onClick={() => void handleStart()}
            className="inline-flex cursor-pointer items-center gap-1.5 rounded-md bg-emerald-600 px-4 py-1.5 text-sm font-semibold text-white transition hover:bg-emerald-500 disabled:cursor-not-allowed disabled:opacity-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500/50"
          >
            <MonitorShareIcon className="h-4 w-4" />
            {busy ? 'Starte …' : 'Live gehen'}
          </button>
        </div>
      </div>
    </div>,
    document.body,
  );
}
