import { useState, useEffect, useRef } from 'react';
import { useSettingsStore } from '../../../stores/settingsStore';
import { useUIStore } from '../../../stores/uiStore';
import type { InstanceStreamingLimits } from '@backspace/shared';
import { Toggle } from '../../ui/Toggle';
import {
  STANDARD_RESOLUTIONS, STANDARD_FRAMERATES,
  ALL_RESOLUTIONS, RESOLUTION_LABELS,
  HIGH_END_RESOLUTION_THRESHOLD, HIGH_END_FRAMERATE_THRESHOLD,
  BITRATE_MATRIX_KBPS,
  type Resolution,
} from '@backspace/shared/src/constants';

function formatKbps(kbps: number): string {
  return kbps >= 1000
    ? `${(kbps / 1000).toFixed(kbps % 1000 === 0 ? 0 : 1)} Mbps`
    : `${kbps} kbps`;
}

export function StreamingPanel() {
  const limits = useSettingsStore((s) => s.streamingLimits);
  const updateStreamingLimits = useSettingsStore((s) => s.updateStreamingLimits);

  const addToast = useUIStore((s) => s.addToast);

  const [draft, setDraft] = useState<InstanceStreamingLimits | null>(null);
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState('');


  // Matrix editor state: full grid of kbps values (integers only)
  const [matrixDraft, setMatrixDraft] = useState<Record<string, number>>({});
  const [editingCell, setEditingCell] = useState<string | null>(null);
  const [scaleValue, setScaleValue] = useState(1.0);
  const scaleSnapshot = useRef<Record<string, number> | null>(null);

  useEffect(() => {
    if (limits) setDraft({ ...limits });
  }, [limits]);

  // Initialize matrix draft from limits + overrides
  useEffect(() => {
    if (!limits) return;
    const matrix: Record<string, number> = {};
    for (const res of STANDARD_RESOLUTIONS) {
      for (const fps of STANDARD_FRAMERATES) {
        const key = `${res}_${fps}`;
        matrix[key] = limits.bitrateMatrixOverrides?.[key] ?? BITRATE_MATRIX_KBPS[res]![fps as number]!;
      }
    }
    setMatrixDraft(matrix);
  }, [limits]);

  if (!draft) return <div className="text-sm text-txt-tertiary">Loading settings...</div>;

  const getDefaultKbps = (key: string): number => {
    const parts = key.split('_').map(Number);
    const h = parts[0]!;
    const f = parts[1]!;
    return BITRATE_MATRIX_KBPS[h]?.[f] ?? 8000;
  };

  const isOverridden = (key: string): boolean => matrixDraft[key] !== getDefaultKbps(key);

  const enabledResolutions = draft.allowedResolutions.filter((r): r is number => r !== 'native');
  const enabledFramerates = draft.allowedFramerates;

  const handleScaleStart = () => {
    scaleSnapshot.current = { ...matrixDraft };
  };

  const handleScaleChange = (newScale: number) => {
    setScaleValue(newScale);
    if (!scaleSnapshot.current) return;
    const scaled: Record<string, number> = {};
    for (const [key, val] of Object.entries(scaleSnapshot.current)) {
      scaled[key] = Math.round(val * newScale);
    }
    setMatrixDraft(scaled);
  };

  const handleScaleEnd = () => {
    scaleSnapshot.current = null;
    setScaleValue(1.0);
  };

  const matrixHasChanges = (() => {
    if (!limits) return false;
    for (const [key, val] of Object.entries(matrixDraft)) {
      const serverVal = limits.bitrateMatrixOverrides?.[key] ?? getDefaultKbps(key);
      if (val !== serverVal) return true;
    }
    return false;
  })();
  const hasChanges = JSON.stringify(draft) !== JSON.stringify(limits) || matrixHasChanges;

  const handleSave = async () => {
    setSaving(true);
    setSaveError('');
    try {
      // Compute sparse overrides: only cells that differ from defaults
      const overrides: Record<string, number> = {};
      for (const [key, val] of Object.entries(matrixDraft)) {
        if (val !== getDefaultKbps(key)) {
          overrides[key] = val;
        }
      }
      const payload = {
        ...draft,
        bitrateMatrixOverrides: Object.keys(overrides).length > 0 ? overrides : null,
      };
      await updateStreamingLimits(payload);
      addToast('Settings saved', 'success', 2000);
    } catch (err) {
      setSaveError(err instanceof Error ? err.message : 'Failed to save');
    } finally {
      setSaving(false);
    }
  };

  const handleReset = () => {
    if (limits) {
      setDraft({ ...limits });
      const matrix: Record<string, number> = {};
      for (const res of STANDARD_RESOLUTIONS) {
        for (const fps of STANDARD_FRAMERATES) {
          const key = `${res}_${fps}`;
          matrix[key] = limits.bitrateMatrixOverrides?.[key] ?? BITRATE_MATRIX_KBPS[res]![fps as number]!;
        }
      }
      setMatrixDraft(matrix);
    }
    setSaveError('');
  };

  const toggleResolution = (res: number | 'native') => {
    const current = new Set(draft.allowedResolutions);
    if (current.has(res)) {
      if (current.size <= 1) return;
      current.delete(res);
    } else {
      current.add(res);
    }
    // Sort: numbers ascending, 'native' always last
    const nums: (number | 'native')[] = Array.from(current).filter((r): r is number => r !== 'native').sort((a, b) => a - b);
    if (current.has('native')) nums.push('native');
    setDraft({ ...draft, allowedResolutions: nums });
  };

  const toggleFramerate = (fps: number) => {
    const current = new Set(draft.allowedFramerates);
    if (current.has(fps)) {
      if (current.size <= 1) return;
      current.delete(fps);
    } else {
      current.add(fps);
    }
    setDraft({ ...draft, allowedFramerates: Array.from(current).sort((a, b) => a - b) });
  };

  const pillBase = 'px-3 py-1.5 rounded text-[13px] font-medium transition-colors cursor-pointer select-none';
  const pillOn = 'bg-accent-primary text-white';
  const pillOff = 'bg-surface-elevated text-txt-secondary hover:bg-interactive-hover';

  return (
    <div className="space-y-5">
      <h2 className="text-lg font-semibold text-txt-primary">Streaming</h2>
      <div className="text-xs text-txt-tertiary">
        These limits apply to all users on this instance. Users can pick values within these bounds.
      </div>

      {/* Bandwidth */}
      <div>
        <div className="text-[11px] font-semibold text-txt-tertiary uppercase tracking-wider mb-1.5">Bandwidth</div>
        <p className="text-xs text-txt-tertiary mb-2">Minimum and maximum bitrate bounds, and the step size for the quality slider.</p>
        <div className="rounded-lg bg-white/[0.02] p-3.5 space-y-4">
          {/* Allow Custom Bitrate */}
          <div className="flex items-center justify-between">
            <div>
              <div className="text-sm text-txt-primary">Allow Custom Bitrate</div>
              <div className="text-xs text-txt-tertiary">Let users set their own bitrate instead of using the matrix defaults</div>
            </div>
            <Toggle
              enabled={draft.allowCustomBitrate}
              onChange={(enabled) => setDraft({ ...draft, allowCustomBitrate: enabled })}
            />
          </div>
          {/* Bitrate Range */}
          <div>
            <div className="text-xs text-txt-secondary mb-1.5">
              Bitrate Range
            </div>
            <div className="flex items-start gap-3">
              <div className="flex-1 space-y-1.5">
                <label className="text-[11px] text-txt-tertiary block">Min</label>
                <input
                  type="range"
                  min={100}
                  max={Math.min(draft.maxBitrateKbps - 500, 100000)}
                  step={100}
                  value={Math.min(draft.minBitrateKbps, 100000)}
                  onChange={(e) => setDraft({ ...draft, minBitrateKbps: Number(e.target.value) })}
                  className="w-full h-1.5 accent-accent-primary cursor-pointer appearance-none bg-interactive-muted rounded-full
                    [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
                    [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-md
                    [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:border-0"
                />
                <div className="flex items-center gap-1.5">
                  <input
                    type="number"
                    min={100}
                    max={1000000}
                    step={100}
                    value={draft.minBitrateKbps}
                    onChange={(e) => {
                      const v = Number(e.target.value);
                      if (v >= 100 && v <= 1000000) setDraft({ ...draft, minBitrateKbps: v });
                    }}
                    className="input-standard w-20 px-2 py-0.5 text-xs"
                  />
                  <span className="text-[11px] text-txt-tertiary">{formatKbps(draft.minBitrateKbps)}</span>
                </div>
              </div>
              <div className="flex-1 space-y-1.5">
                <label className="text-[11px] text-txt-tertiary block">Max</label>
                <input
                  type="range"
                  min={draft.minBitrateKbps + 500}
                  max={100000}
                  step={500}
                  value={Math.min(draft.maxBitrateKbps, 100000)}
                  onChange={(e) => setDraft({ ...draft, maxBitrateKbps: Number(e.target.value) })}
                  className="w-full h-1.5 accent-accent-primary cursor-pointer appearance-none bg-interactive-muted rounded-full
                    [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
                    [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-md
                    [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:border-0"
                />
                <div className="flex items-center gap-1.5">
                  <input
                    type="number"
                    min={draft.minBitrateKbps + 500}
                    max={1000000}
                    step={500}
                    value={draft.maxBitrateKbps}
                    onChange={(e) => {
                      const v = Number(e.target.value);
                      if (v >= 500 && v <= 1000000) setDraft({ ...draft, maxBitrateKbps: v });
                    }}
                    className="input-standard w-20 px-2 py-0.5 text-xs"
                  />
                  <span className="text-[11px] text-txt-tertiary">{formatKbps(draft.maxBitrateKbps)}</span>
                </div>
              </div>
            </div>
          </div>

          {/* Bitrate Step — presets + custom input */}
          <div className="pt-2 border-t border-white/[0.04]">
            <div className="flex items-center gap-2 mb-1.5">
              <span className="text-[11px] text-txt-tertiary">Slider Step</span>
              <input
                type="number"
                min={50}
                max={10000}
                step={50}
                value={draft.bitrateStepKbps}
                onChange={(e) => {
                  const v = Number(e.target.value);
                  if (v >= 50 && v <= 10000) setDraft({ ...draft, bitrateStepKbps: v });
                }}
                className="input-standard w-14 px-1.5 py-0 text-[11px] text-center"
              />
              <span className="text-[11px] text-txt-tertiary">kbps</span>
            </div>
            <div className="flex flex-wrap gap-1">
              {[100, 250, 500, 1000, 2500, 5000].map((step) => (
                <button
                  key={step}
                  onClick={() => setDraft({ ...draft, bitrateStepKbps: step })}
                  className={`px-2 py-0.5 rounded text-[11px] font-medium transition-colors cursor-pointer select-none ${
                    draft.bitrateStepKbps === step
                      ? 'bg-accent-primary text-white'
                      : 'bg-surface-elevated text-txt-secondary hover:bg-interactive-hover'
                  }`}
                >
                  {step >= 1000 ? `${step / 1000} Mbps` : `${step} kbps`}
                </button>
              ))}
            </div>
          </div>
        </div>
      </div>

      {/* Quality */}
      <div>
        <div className="text-[11px] font-semibold text-txt-tertiary uppercase tracking-wider mb-1.5">Quality</div>
        <p className="text-xs text-txt-tertiary mb-2">Available resolution and frame rate options for screen sharing.</p>
        <div className="rounded-lg bg-white/[0.02] p-3.5 space-y-4">
          {/* Allowed Resolutions */}
          <div>
            <div className="text-xs text-txt-secondary mb-1.5">
              Allowed Resolutions
            </div>
            <div className="flex flex-wrap gap-1.5">
              {ALL_RESOLUTIONS.map((res) => (
                <button
                  key={String(res)}
                  onClick={() => toggleResolution(res)}
                  className={`${pillBase} ${draft.allowedResolutions.includes(res) ? pillOn : pillOff}`}
                >
                  {RESOLUTION_LABELS[res]}
                </button>
              ))}
            </div>
          </div>

          {/* Allowed Frame Rates */}
          <div>
            <div className="text-xs text-txt-secondary mb-1.5">
              Allowed Frame Rates
            </div>
            <div className="flex flex-wrap gap-1.5">
              {STANDARD_FRAMERATES.map((fps) => (
                <button
                  key={fps}
                  onClick={() => toggleFramerate(fps)}
                  className={`${pillBase} ${draft.allowedFramerates.includes(fps) ? pillOn : pillOff}`}
                >
                  {fps} fps
                </button>
              ))}
            </div>
          </div>
        </div>
      </div>

      {/* High-end resource warning */}
      {(draft.allowedResolutions.some(
          (r) => r === 'native' || (typeof r === 'number' && r >= HIGH_END_RESOLUTION_THRESHOLD)
        ) || draft.allowedFramerates.some(
          (f) => f >= HIGH_END_FRAMERATE_THRESHOLD
        )) && (
        <div className="p-3 bg-accent-amber/10 border border-accent-amber/30 rounded-lg">
          <div className="flex items-start gap-2">
            <svg className="w-4 h-4 text-accent-amber mt-0.5 shrink-0" viewBox="0 0 20 20" fill="currentColor">
              <path fillRule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.168 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
            </svg>
            <div className="text-xs text-accent-amber/90 leading-relaxed">
              <span className="font-semibold">High-performance settings enabled.</span>{' '}
              Streaming above 1080p or 60 fps requires significant client-side CPU/GPU encoding
              power and can saturate server bandwidth, especially when streams are routed through
              TURN. High-end configurations (e.g., 4K at 120 fps) can require up to 45 Mbps per
              active stream. Ensure your infrastructure can handle this load before enabling these
              options for all users.
            </div>
          </div>
        </div>
      )}

      {/* Bitrate Matrix */}
      <div>
        <div className="text-[11px] font-semibold text-txt-tertiary uppercase tracking-wider mb-1.5">Bitrate Matrix</div>
        <p className="text-xs text-txt-tertiary mb-2">Default bitrates per resolution and frame rate. Edit individual cells or scale all values at once.</p>
        <div className="rounded-lg bg-white/[0.02] p-3.5 space-y-4">
          {/* Scale slider */}
          <div>
            <div className="flex items-center justify-between mb-1.5">
              <div className="text-xs text-txt-secondary">Scale All</div>
              <div className="text-xs text-txt-tertiary font-mono">&times;{scaleValue.toFixed(2)}</div>
            </div>
            <input
              type="range"
              min={0.5}
              max={2.0}
              step={0.05}
              value={scaleValue}
              onPointerDown={handleScaleStart}
              onChange={(e) => handleScaleChange(Number(e.target.value))}
              onPointerUp={handleScaleEnd}
              onPointerCancel={handleScaleEnd}
              className="w-full h-1.5 accent-accent-primary cursor-pointer appearance-none bg-interactive-muted rounded-full
                [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
                [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-md
                [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:border-0"
            />
            <div className="text-[10px] text-txt-tertiary mt-0.5">Drag to scale all bitrates. Fine-tune individual cells below.</div>
          </div>

          {/* Matrix grid */}
          <div className="overflow-x-auto">
            <table className="w-full text-xs">
              <thead>
                <tr>
                  <th className="text-left text-txt-tertiary font-normal pb-1.5 pr-2"></th>
                  {enabledFramerates.map((fps) => (
                    <th key={fps} className="text-center text-txt-tertiary font-normal pb-1.5 px-1 min-w-[52px]">{fps} fps</th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {enabledResolutions.map((res) => (
                  <tr key={res}>
                    <td className="text-txt-secondary font-medium pr-2 py-0.5">{RESOLUTION_LABELS[res as Resolution] ?? `${res}p`}</td>
                    {enabledFramerates.map((fps) => {
                      const key = `${res}_${fps}`;
                      const val = matrixDraft[key] ?? getDefaultKbps(key);
                      const overridden = isOverridden(key);
                      const exceedsCap = val > draft.maxBitrateKbps;

                      return (
                        <td key={key} className="px-1 py-0.5">
                          {editingCell === key ? (
                            <input
                              autoFocus
                              type="number"
                              step={0.1}
                              className="input-standard w-full px-1.5 py-0.5 text-xs text-center"
                              defaultValue={(val / 1000).toFixed(1)}
                              onBlur={(e) => {
                                const mbps = parseFloat(e.target.value);
                                if (!isNaN(mbps) && mbps > 0) {
                                  setMatrixDraft({ ...matrixDraft, [key]: Math.round(mbps * 1000) });
                                }
                                setEditingCell(null);
                              }}
                              onKeyDown={(e) => {
                                if (e.key === 'Enter') (e.target as HTMLInputElement).blur();
                                if (e.key === 'Escape') setEditingCell(null);
                              }}
                            />
                          ) : (
                            <button
                              onClick={() => setEditingCell(key)}
                              className={`w-full px-1.5 py-0.5 rounded text-center transition-colors
                                ${exceedsCap ? 'bg-accent-amber/10 text-accent-amber' : ''}
                                ${overridden && !exceedsCap ? 'bg-accent-primary/10 text-accent-primary' : ''}
                                ${!overridden && !exceedsCap ? 'text-txt-secondary hover:bg-interactive-hover' : ''}
                              `}
                              title={overridden ? `Default: ${(getDefaultKbps(key) / 1000).toFixed(1)} Mbps (click \u00d7 to reset)` : 'Click to edit'}
                            >
                              {(val / 1000).toFixed(1)}
                              {overridden && (
                                <span
                                  className="ml-1 text-[10px] text-txt-tertiary hover:text-txt-danger cursor-pointer"
                                  onClick={(e) => {
                                    e.stopPropagation();
                                    setMatrixDraft({ ...matrixDraft, [key]: getDefaultKbps(key) });
                                  }}
                                >
                                  &times;
                                </span>
                              )}
                            </button>
                          )}
                        </td>
                      );
                    })}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>

          {/* Reset all button */}
          {Object.entries(matrixDraft).some(([key, val]) => val !== getDefaultKbps(key)) && (
            <button
              onClick={() => {
                const reset: Record<string, number> = {};
                for (const [key] of Object.entries(matrixDraft)) {
                  reset[key] = getDefaultKbps(key);
                }
                setMatrixDraft(reset);
              }}
              className="text-[11px] text-accent-primary hover:text-accent-lavender transition-colors"
            >
              Reset all to defaults
            </button>
          )}
        </div>
      </div>

      {/* Coherence warning */}
      {Object.entries(matrixDraft).some(([, val]) => val > draft.maxBitrateKbps) && (
        <div className="p-3 bg-accent-amber/10 border border-accent-amber/30 rounded-lg">
          <div className="flex items-start gap-2">
            <svg className="w-4 h-4 text-accent-amber mt-0.5 shrink-0" viewBox="0 0 20 20" fill="currentColor">
              <path fillRule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.168 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 6a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 6zm0 9a1 1 0 100-2 1 1 0 000 2z" clipRule="evenodd" />
            </svg>
            <div className="text-xs text-accent-amber/90 leading-relaxed">
              <span className="font-semibold">Matrix values exceed global cap.</span>{' '}
              Some bitrate values exceed your maximum of {formatKbps(draft.maxBitrateKbps)}.
              Streams at those combos will be quality-degraded to your cap.
            </div>
          </div>
        </div>
      )}

      {/* Save / Reset */}
      {saveError && (
        <div className="p-2 bg-accent-rose/10 border border-accent-rose/30 rounded text-txt-danger text-sm">{saveError}</div>
      )}
      {hasChanges && (
        <div className="sticky bottom-0 z-10 pointer-events-none">
          <div className="flex justify-center pt-3 pb-1">
            <div className="glass-bubble rounded-full px-4 py-2 flex items-center gap-2 animate-slide-up pointer-events-auto">
              <button
                onClick={handleReset}
                className="px-3 py-1 text-sm text-txt-tertiary hover:text-txt-secondary transition-colors"
              >
                Reset
              </button>
              <button
                onClick={handleSave}
                disabled={saving}
                className="px-3 py-1.5 bg-accent-primary hover:bg-accent-primary/80 text-white text-sm font-medium rounded-full transition-colors disabled:opacity-50"
              >
                {saving ? 'Saving...' : 'Save'}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
