﻿import DateTimePicker, { DateTimePickerEvent } from "@react-native-community/datetimepicker";
import * as ImagePicker from "expo-image-picker";
import { useEffect, useState } from "react";
import {
  ActivityIndicator,
  Alert,
  Modal,
  Platform,
  ScrollView,
  StyleSheet,
  Switch,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from "react-native";
import { useRouter } from "../router";
import { colors } from "../styles";

const BASE_URL =
  "https://shsf-api.reversed.dev/api/exec/15/1c44d8b5-4065-4a54-b259-748561021329";

// ─── Types ────────────────────────────────────────────────────────────────────

export type CardType = "custom_json" | "static_text" | "clock" | "image_rotator";

/** 4-column Ã— 4-row grid, 1-based */
export interface CardLayout {
  grid_col: number;
  grid_row: number;
  col_span: number;
  row_span: number;
}

// custom_json
interface DataCardConfig {
  url: string;
  refresh_interval: number;
  display_options: { font_size: number; text_color: string };
  take?: string;
  additional_headers?: Record<string, string>;
}
interface CustomJsonCard {
  id: string; type: "custom_json"; name: string;
  config: DataCardConfig; layout?: CardLayout;
}

// static_text
interface StaticTextCard {
  id: string; type: "static_text"; name: string;
  config: { text: string; font_size: number; text_color: string };
  layout?: CardLayout;
}

// clock
interface ClockCard {
  id: string; type: "clock"; name: string;
  config: {
    mode: "time" | "timer";
    timezone?: string;
    target_iso?: string;
    font_size: number;
    text_color: string;
    show_seconds?: boolean;
  };
  layout?: CardLayout;
}

// image_rotator
interface ImageRotatorCard {
  id: string; type: "image_rotator"; name: string;
  config: { images: string[]; interval: number; fit: "cover" | "contain" };
  layout?: CardLayout;
}

export type DataCard = CustomJsonCard | StaticTextCard | ClockCard | ImageRotatorCard;

// ─── Flat form state ──────────────────────────────────────────────────────────

interface FormState {
  type: CardType;
  name: string;
  // layout
  grid_col: number; grid_row: number; col_span: number; row_span: number;
  // display (custom_json / static_text / clock)
  font_size: string;
  text_color: string;
  // custom_json
  url: string;
  refresh_interval: string;
  take: string;
  headers: string;
  // static_text
  static_text: string;
  // clock
  clock_mode: "time" | "timer";
  clock_timezone: string;
  clock_target_iso: string;
  clock_show_seconds: boolean;
  // image_rotator
  image_urls: string[];
  image_interval: string;
  image_fit: "cover" | "contain";
}

const EMPTY_FORM: FormState = {
  type: "custom_json",
  name: "",
  grid_col: 1, grid_row: 1, col_span: 1, row_span: 1,
  font_size: "16",
  text_color: "#ffffff",
  url: "",
  refresh_interval: "60",
  take: "",
  headers: "",
  static_text: "",
  clock_mode: "time",
  clock_timezone: "Europe/London",
  clock_target_iso: "",
  clock_show_seconds: true,
  image_urls: [],
  image_interval: "10",
  image_fit: "cover",
};

// ─── Helpers ──────────────────────────────────────────────────────────────────

function parseHeaders(text: string): Record<string, string> | undefined {
  const result: Record<string, string> = {};
  let hasAny = false;
  for (const line of text.split("\n")) {
    const colonIdx = line.indexOf(":");
    if (colonIdx === -1) continue;
    const key = line.slice(0, colonIdx).trim();
    const value = line.slice(colonIdx + 1).trim();
    if (key) { result[key] = value; hasAny = true; }
  }
  return hasAny ? result : undefined;
}

function headersToText(headers: Record<string, string> | undefined): string {
  if (!headers) return "";
  return Object.entries(headers)
    .map(([k, v]) => `${k}: ${v}`)
    .join("\n");
}

function cardToForm(card: DataCard): FormState {
  const base: FormState = {
    ...EMPTY_FORM,
    type: card.type,
    name: card.name,
    grid_col: card.layout?.grid_col ?? 1,
    grid_row: card.layout?.grid_row ?? 1,
    col_span: card.layout?.col_span ?? 1,
    row_span: card.layout?.row_span ?? 1,
  };
  if (card.type === "static_text") {
    return {
      ...base,
      static_text: card.config.text,
      font_size: String(card.config.font_size ?? 16),
      text_color: card.config.text_color ?? "#ffffff",
    };
  }
  if (card.type === "clock") {
    return {
      ...base,
      clock_mode: card.config.mode,
      clock_timezone: card.config.timezone ?? "",
      clock_target_iso: card.config.target_iso ?? "",
      clock_show_seconds: card.config.show_seconds !== false,
      font_size: String(card.config.font_size ?? 48),
      text_color: card.config.text_color ?? "#ffffff",
    };
  }
  if (card.type === "image_rotator") {
    return {
      ...base,
      image_urls: card.config.images ?? [],
      image_interval: String(card.config.interval ?? 10),
      image_fit: card.config.fit ?? "cover",
    };
  }
  // custom_json
  return {
    ...base,
    url: (card as CustomJsonCard).config.url,
    refresh_interval: String((card as CustomJsonCard).config.refresh_interval),
    font_size: String((card as CustomJsonCard).config.display_options?.font_size ?? 16),
    text_color: (card as CustomJsonCard).config.display_options?.text_color ?? "#ffffff",
    take: (card as CustomJsonCard).config.take ?? "",
    headers: headersToText((card as CustomJsonCard).config.additional_headers),
  };
}

function formToCard(form: FormState, id: string): DataCard {
  const layout: CardLayout = {
    grid_col: form.grid_col, grid_row: form.grid_row,
    col_span: form.col_span, row_span: form.row_span,
  };
  if (form.type === "static_text") {
    return {
      id, type: "static_text", name: form.name.trim(),
      config: {
        text: form.static_text,
        font_size: Math.max(8, parseInt(form.font_size, 10) || 16),
        text_color: form.text_color.trim() || "#ffffff",
      },
      layout,
    };
  }
  if (form.type === "clock") {
    return {
      id, type: "clock", name: form.name.trim(),
      config: {
        mode: form.clock_mode,
        timezone: form.clock_timezone.trim() || undefined,
        target_iso: form.clock_mode === "timer" ? form.clock_target_iso.trim() || undefined : undefined,
        font_size: Math.max(8, parseInt(form.font_size, 10) || 48),
        text_color: form.text_color.trim() || "#ffffff",
        show_seconds: form.clock_show_seconds,
      },
      layout,
    };
  }
  if (form.type === "image_rotator") {
    return {
      id, type: "image_rotator", name: form.name.trim(),
      config: {
        images: form.image_urls,
        interval: Math.max(2, parseInt(form.image_interval, 10) || 10),
        fit: form.image_fit,
      },
      layout,
    };
  }
  // custom_json
  return {
    id, type: "custom_json", name: form.name.trim(),
    config: {
      url: form.url.trim(),
      refresh_interval: Math.max(5, parseInt(form.refresh_interval, 10) || 60),
      display_options: {
        font_size: Math.max(8, parseInt(form.font_size, 10) || 16),
        text_color: form.text_color.trim() || "#ffffff",
      },
      take: form.take.trim() || undefined,
      additional_headers: parseHeaders(form.headers),
    },
    layout,
  };
}

function genId() {
  return Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
}

// ─── Grid Picker ──────────────────────────────────────────────────────────────────

const GRID_COLS = 4;
const GRID_ROWS = 4;

interface GridPickerProps {
  gridCol: number;
  gridRow: number;
  colSpan: number;
  rowSpan: number;
  /** Layouts of other (already-placed) cards to show as occupied cells */
  otherLayouts?: Array<{ name: string; layout: CardLayout }>;
  onChange: (gridCol: number, gridRow: number, colSpan: number, rowSpan: number) => void;
}

function GridPicker({ gridCol, gridRow, colSpan, rowSpan, otherLayouts, onChange }: GridPickerProps) {
  // Phase: "start" = next tap sets the top-left; "end" = next tap extends/sets bottom-right
  const [phase, setPhase] = useState<"start" | "end">("start");

  const endCol = gridCol + colSpan - 1;
  const endRow = gridRow + rowSpan - 1;

  const handleCellTap = (col: number, row: number) => {
    if (phase === "start") {
      // First tap: place a 1Ã—1 at this cell and wait for the end tap
      onChange(col, row, 1, 1);
      setPhase("end");
    } else {
      // Second tap
      if (col >= gridCol && row >= gridRow) {
        // Extend the selection
        onChange(gridCol, gridRow, col - gridCol + 1, row - gridRow + 1);
      } else {
        // Reset to new 1Ã—1 at the tapped cell
        onChange(col, row, 1, 1);
      }
      setPhase("start");
    }
  };

  const colLabels = ["1", "2", "3", "4"];
  const rowLabels = ["1", "2", "3", "4"];

  return (
    <View style={gridStyles.container}>
      {/* Phase indicator banner */}
      <View style={[gridStyles.phaseBanner, phase === "end" && gridStyles.phaseBannerEnd]}>
        <Text style={[gridStyles.phaseIcon]}>{phase === "start" ? "↖" : "↘"}</Text>
        <View style={{ flex: 1 }}>
          <Text style={[gridStyles.phaseTitle, phase === "end" && gridStyles.phaseTitleEnd]}>
            {phase === "start" ? "Step 1 — Pick top-left corner" : "Step 2 — Pick bottom-right corner"}
          </Text>
        </View>
        <View style={[gridStyles.phasePill, phase === "end" && gridStyles.phasePillEnd]}>
          <Text style={[gridStyles.phasePillText, phase === "end" && gridStyles.phasePillTextEnd]}>
            {phase === "start" ? "1 / 2" : "2 / 2"}
          </Text>
        </View>
      </View>

      {/* Column labels */}
      <View style={gridStyles.colLabels}>
        <View style={gridStyles.rowLabelSpacer} />
        {colLabels.map((l, ci) => (
          <View key={ci} style={gridStyles.colLabel}>
            <Text style={gridStyles.axisLabel}>{l}</Text>
          </View>
        ))}
      </View>

      {Array.from({ length: GRID_ROWS }, (_, ri) => (
        <View key={ri} style={gridStyles.row}>
          {/* Row label */}
          <View style={gridStyles.rowLabel}>
            <Text style={gridStyles.axisLabel}>{rowLabels[ri]}</Text>
          </View>
          {Array.from({ length: GRID_COLS }, (_, ci) => {
            const col = ci + 1;
            const row = ri + 1;
            const selected =
              col >= gridCol && col <= endCol && row >= gridRow && row <= endRow;
            const isStart = col === gridCol && row === gridRow;
            const occupiedBy = (otherLayouts ?? []).find(
              ({ layout: l }) =>
                col >= l.grid_col && col <= l.grid_col + l.col_span - 1 &&
                row >= l.grid_row && row <= l.grid_row + l.row_span - 1
            );
            return (
              <TouchableOpacity
                key={ci}
                style={[
                  gridStyles.cell,
                  !!occupiedBy && gridStyles.cellOccupied,
                  selected && gridStyles.cellSelected,
                  isStart && gridStyles.cellStart,
                ]}
                onPress={() => handleCellTap(col, row)}
                activeOpacity={0.7}
              >
                {isStart && <Text style={gridStyles.cellStartDot}>•</Text>}
                {!!occupiedBy && !selected && (
                  <Text style={gridStyles.cellOccupiedLabel} numberOfLines={1}>
                    {occupiedBy.name.slice(0, 4)}
                  </Text>
                )}
              </TouchableOpacity>
            );
          })}
        </View>
      ))}

      <Text style={gridStyles.hint}>
        Size: {colSpan}×{rowSpan}{colSpan === 1 && rowSpan === 1 ? " (1×1)" : ` – ${colSpan * rowSpan} cells`}
      </Text>
    </View>
  );
}

const gridStyles = StyleSheet.create({
  container: {
    gap: 6,
  },
  phaseBanner: {
    flexDirection: "row",
    alignItems: "center",
    gap: 8,
    borderRadius: 10,
    borderWidth: 1.5,
    borderColor: colors.border,
    backgroundColor: colors.surface,
    paddingVertical: 10,
    paddingHorizontal: 12,
  },
  phaseBannerEnd: {
    borderColor: colors.accent,
    backgroundColor: colors.accent + "18",
  },
  phaseIcon: {
    fontSize: 18,
    width: 24,
    textAlign: "center",
    color: colors.textMuted,
  },
  phaseTitle: {
    fontSize: 13,
    fontWeight: "600",
    color: colors.textSecondary,
  },
  phaseTitleEnd: {
    color: colors.accent,
  },
  phasePill: {
    borderRadius: 20,
    paddingHorizontal: 8,
    paddingVertical: 3,
    backgroundColor: colors.surfaceElevated,
    borderWidth: 1,
    borderColor: colors.border,
  },
  phasePillEnd: {
    backgroundColor: colors.accent + "33",
    borderColor: colors.accent,
  },
  phasePillText: {
    fontSize: 11,
    fontWeight: "700",
    color: colors.textMuted,
  },
  phasePillTextEnd: {
    color: colors.accent,
  },
  colLabels: {
    flexDirection: "row",
    marginBottom: 2,
  },
  colLabel: {
    flex: 1,
    alignItems: "center",
  },
  rowLabelSpacer: {
    width: 22,
  },
  row: {
    flexDirection: "row",
    gap: 4,
    alignItems: "center",
  },
  rowLabel: {
    width: 18,
    alignItems: "center",
  },
  axisLabel: {
    fontSize: 10,
    color: colors.textMuted,
    fontWeight: "600",
  },
  cell: {
    flex: 1,
    aspectRatio: 1,
    borderRadius: 6,
    borderWidth: 1,
    borderColor: colors.border,
    backgroundColor: colors.surface,
    alignItems: "center",
    justifyContent: "center",
  },
  cellSelected: {
    backgroundColor: colors.accent + "44",
    borderColor: colors.accent,
  },
  cellStart: {
    backgroundColor: colors.accent + "88",
    borderColor: colors.accent,
  },
  cellStartDot: {
    fontSize: 16,
    color: colors.accent,
    lineHeight: 18,
  },
  cellOccupied: {
    backgroundColor: colors.dangerBg,
    borderColor: colors.dangerBorder,
  },
  cellOccupiedLabel: {
    fontSize: 8,
    color: colors.dangerText,
    textAlign: "center",
    fontWeight: "600",
  },
  hint: {
    fontSize: 11,
    color: colors.textMuted,
    marginTop: 2,
  },
});

// ─── Type selector ────────────────────────────────────────────────────────────

const CARD_TYPES: { type: CardType; label: string; icon: string; desc: string }[] = [
  { type: "custom_json",    label: "JSON Feed",        icon: "⚡", desc: "Live data from any JSON API" },
  { type: "static_text",   label: "Static Text",       icon: "📝", desc: "Fixed text or note" },
  { type: "clock",         label: "Clock / Timer",     icon: "🕐", desc: "Live time or countdown" },
  { type: "image_rotator", label: "Image Slideshow",   icon: "🖼", desc: "Rotating image gallery" },
];

interface TypeSelectorProps {
  selected: CardType;
  disabled?: boolean;
  onSelect: (t: CardType) => void;
}

function TypeSelector({ selected, disabled, onSelect }: TypeSelectorProps) {
  return (
    <View style={{ gap: 8 }}>
      {CARD_TYPES.map(({ type, label, icon, desc }) => (
        <TouchableOpacity
          key={type}
          style={[typeSelStyles.row, selected === type && typeSelStyles.rowSelected, disabled && typeSelStyles.rowDisabled]}
          onPress={() => !disabled && onSelect(type)}
          activeOpacity={disabled ? 1 : 0.75}
        >
          <Text style={typeSelStyles.icon}>{icon}</Text>
          <View style={{ flex: 1 }}>
            <Text style={[typeSelStyles.label, selected === type && typeSelStyles.labelSelected]}>{label}</Text>
            <Text style={typeSelStyles.desc}>{desc}</Text>
          </View>
          {selected === type && <Text style={typeSelStyles.check}>✓</Text>}
        </TouchableOpacity>
      ))}
    </View>
  );
}

const typeSelStyles = StyleSheet.create({
  row: { flexDirection: "row", alignItems: "center", gap: 12, borderRadius: 12, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.surface, padding: 12 },
  rowSelected: { borderColor: colors.accent, backgroundColor: colors.accent + "18" },
  rowDisabled: { opacity: 0.5 },
  icon: { fontSize: 22, width: 32, textAlign: "center" },
  label: { fontSize: 15, fontWeight: "600", color: colors.textPrimary },
  labelSelected: { color: colors.accent },
  desc: { fontSize: 12, color: colors.textMuted, marginTop: 1 },
  check: { fontSize: 16, color: colors.accent, fontWeight: "700" },
});

// ─── Type-specific form sections ──────────────────────────────────────────────

function SectionLabel({ text }: { text: string }) {
  return <Text style={styles.sectionLabel}>{text}</Text>;
}

function FieldLabel({ text }: { text: string }) {
  return <Text style={styles.label}>{text}</Text>;
}

function CustomJsonFields({ form, onChange }: { form: FormState; onChange: (k: keyof FormState, v: string) => void }) {
  return (
    <>
      <View style={styles.field}>
        <FieldLabel text="JSON URL *" />
        <TextInput style={styles.input} placeholder="https://api.example.com/data" placeholderTextColor={colors.placeholderColor} value={form.url} onChangeText={(v) => onChange("url", v)} autoCapitalize="none" keyboardType="url" />
      </View>
      <View style={styles.field}>
        <FieldLabel text="Refresh Interval (seconds)" />
        <TextInput style={styles.input} placeholder="60" placeholderTextColor={colors.placeholderColor} value={form.refresh_interval} onChangeText={(v) => onChange("refresh_interval", v)} keyboardType="numeric" />
      </View>
      <SectionLabel text="Advanced" />
      <View style={styles.field}>
        <FieldLabel text="Value Path (optional)" />
        <Text style={styles.hint}>Extract a nested value, e.g. <Text style={styles.code}>$out.data.temperature</Text></Text>
        <TextInput style={styles.input} placeholder="$out.data.value" placeholderTextColor={colors.placeholderColor} value={form.take} onChangeText={(v) => onChange("take", v)} autoCapitalize="none" />
      </View>
      <View style={styles.field}>
        <FieldLabel text="Additional Headers (optional)" />
        <Text style={styles.hint}>One per line: Key: Value</Text>
        <TextInput style={[styles.input, styles.multilineInput]} placeholder={"Authorization: Bearer token123\nX-API-Key: mykey"} placeholderTextColor={colors.placeholderColor} value={form.headers} onChangeText={(v) => onChange("headers", v)} multiline autoCapitalize="none" />
      </View>
    </>
  );
}

function StaticTextFields({ form, onChange }: { form: FormState; onChange: (k: keyof FormState, v: string) => void }) {
  return (
    <View style={styles.field}>
      <FieldLabel text="Text *" />
      <TextInput
        style={[styles.input, styles.multilineInput, { minHeight: 120 }]}
        placeholder="Enter the text to display on the TV…"
        placeholderTextColor={colors.placeholderColor}
        value={form.static_text}
        onChangeText={(v) => onChange("static_text", v)}
        multiline
        textAlignVertical="top"
      />
    </View>
  );
}

interface ClockFieldsProps {
  form: FormState;
  onChange: (k: keyof FormState, v: string) => void;
  onBoolChange: (k: keyof FormState, v: boolean) => void;
}

function ClockFields({ form, onChange, onBoolChange }: ClockFieldsProps) {
  return (
    <>
      <View style={styles.field}>
        <FieldLabel text="Mode" />
        <View style={styles.segRow}>
          {(["time", "timer"] as const).map((m) => (
            <TouchableOpacity
              key={m}
              style={[styles.segBtn, form.clock_mode === m && styles.segBtnActive]}
              onPress={() => onChange("clock_mode", m)}
              activeOpacity={0.75}
            >
              <Text style={[styles.segBtnText, form.clock_mode === m && styles.segBtnTextActive]}>
                {m === "time" ? "🕐  Live Time" : "⏱  Countdown"}
              </Text>
            </TouchableOpacity>
          ))}
        </View>
      </View>
      <View style={styles.field}>
        <FieldLabel text={form.clock_mode === "time" ? "Timezone (IANA)" : "Timezone for target display"} />
        <TextInput style={styles.input} placeholder="Europe/Berlin" placeholderTextColor={colors.placeholderColor} value={form.clock_timezone} onChangeText={(v) => onChange("clock_timezone", v)} autoCapitalize="none" />
        <Text style={styles.hint}>e.g. Europe/Berlin · America/New_York · Asia/Tokyo</Text>
      </View>
      {form.clock_mode === "time" && (
        <View style={[styles.field, styles.row, { alignItems: "center" }]}>
          <Text style={[styles.label, { flex: 1 }]}>Show Seconds</Text>
          <Switch
            value={form.clock_show_seconds}
            onValueChange={(v) => onBoolChange("clock_show_seconds", v)}
            trackColor={{ true: colors.accent, false: colors.border }}
            thumbColor="#fff"
          />
        </View>
      )}
      {form.clock_mode === "timer" && (
        <TargetDateTimePicker
          value={form.clock_target_iso}
          onChange={(iso) => onChange("clock_target_iso", iso)}
        />
      )}
    </>
  );
}

// ─── Target date/time picker ──────────────────────────────────────────────────

function TargetDateTimePicker({ value, onChange }: { value: string; onChange: (iso: string) => void }) {
  const parsed = value ? new Date(value) : null;
  const validDate = parsed && !isNaN(parsed.getTime()) ? parsed : new Date();

  // Android: two-step (date then time)
  const [showDate, setShowDate] = useState(false);
  const [showTime, setShowTime] = useState(false);
  const [pendingDate, setPendingDate] = useState<Date>(validDate);

  // iOS: show modal with datetime spinner
  const [showIOS, setShowIOS] = useState(false);
  const [iosDate, setIosDate] = useState<Date>(validDate);

  const displayStr = parsed && !isNaN(parsed.getTime())
    ? parsed.toLocaleString("en-GB", { day: "2-digit", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit", hour12: false })
    : "Tap to pick date & time";

  const toISO = (d: Date) => {
    const pad = (n: number) => String(n).padStart(2, "0");
    return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
  };

  const openPicker = () => {
    if (Platform.OS === "ios") {
      setIosDate(validDate);
      setShowIOS(true);
    } else {
      setPendingDate(validDate);
      setShowDate(true);
    }
  };

  const onDateChange = (_: DateTimePickerEvent, selected?: Date) => {
    setShowDate(false);
    if (selected) {
      setPendingDate(selected);
      setShowTime(true);
    }
  };

  const onTimeChange = (_: DateTimePickerEvent, selected?: Date) => {
    setShowTime(false);
    if (selected) {
      const combined = new Date(pendingDate);
      combined.setHours(selected.getHours(), selected.getMinutes(), 0, 0);
      onChange(toISO(combined));
    }
  };

  return (
    <View style={styles.field}>
      <FieldLabel text="Target Date/Time *" />
      <TouchableOpacity style={styles.datePickerBtn} onPress={openPicker} activeOpacity={0.75}>
        <Text style={styles.datePickerBtnText}>{displayStr}</Text>
      </TouchableOpacity>

      {/* Android: two-step pickers */}
      {Platform.OS !== "ios" && showDate && (
        <DateTimePicker mode="date" value={pendingDate} onChange={onDateChange} />
      )}
      {Platform.OS !== "ios" && showTime && (
        <DateTimePicker mode="time" value={pendingDate} onChange={onTimeChange} is24Hour />
      )}

      {/* iOS: modal with datetime spinner */}
      {Platform.OS === "ios" && (
        <Modal transparent animationType="slide" visible={showIOS} onRequestClose={() => setShowIOS(false)}>
          <View style={styles.iosPickerOverlay}>
            <View style={styles.iosPickerSheet}>
              <View style={styles.iosPickerHeader}>
                <TouchableOpacity onPress={() => setShowIOS(false)}>
                  <Text style={{ color: colors.textMuted, fontSize: 16 }}>Cancel</Text>
                </TouchableOpacity>
                <TouchableOpacity onPress={() => { onChange(toISO(iosDate)); setShowIOS(false); }}>
                  <Text style={{ color: colors.accent, fontSize: 16, fontWeight: "600" }}>Done</Text>
                </TouchableOpacity>
              </View>
              <DateTimePicker
                mode="datetime"
                value={iosDate}
                onChange={(_, d) => d && setIosDate(d)}
                display="spinner"
                style={{ width: "100%" }}
              />
            </View>
          </View>
        </Modal>
      )}
    </View>
  );
}

// ─── Image Rotator Fields ─────────────────────────────────────────────────────

interface ImageRotatorFieldsProps {
  form: FormState;
  onChange: (k: keyof FormState, v: string) => void;
  onUrlsChange: (urls: string[]) => void;
}

function ImageRotatorFields({ form, onChange, onUrlsChange }: ImageRotatorFieldsProps) {
  const [urlInput, setUrlInput] = useState("");
  const [uploading, setUploading] = useState(false);

  const addUrl = () => {
    const url = urlInput.trim();
    if (!url) return;
    onUrlsChange([...form.image_urls, url]);
    setUrlInput("");
  };

  const removeUrl = (idx: number) => {
    onUrlsChange(form.image_urls.filter((_, i) => i !== idx));
  };

  const pickAndUpload = async () => {
    const { granted } = await ImagePicker.requestMediaLibraryPermissionsAsync();
    if (!granted) {
      Alert.alert("Permission required", "Allow access to your photo library to upload images.");
      return;
    }
    const result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: "images",
      quality: 1,
      base64: true,
    });
    if (result.canceled) return;
    const asset = result.assets[0];
    if (!asset.base64) { Alert.alert("Error", "Could not read image data."); return; }
    const ext = (asset.mimeType?.split("/")[1] ?? asset.uri.split(".").pop() ?? "jpg").toLowerCase();
    setUploading(true);
    try {
      const res = await fetch(`${BASE_URL}/push_upload_images`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ images: [{ image_b64: asset.base64, ext }] }),
      });
      const data = await res.json();
      if (data.status !== "success") throw new Error(data.message ?? "Upload failed");
      onUrlsChange([...form.image_urls, ...(data.urls ?? [])]);
    } catch (e) {
      Alert.alert("Upload Failed", String(e));
    } finally {
      setUploading(false);
    }
  };

  return (
    <>
      {form.image_urls.length > 0 && (
        <View style={styles.field}>
          <FieldLabel text={`Images (${form.image_urls.length})`} />
          {form.image_urls.map((url, idx) => (
            <View key={idx} style={imgStyles.urlRow}>
              <Text style={imgStyles.urlText} numberOfLines={1}>{url}</Text>
              <TouchableOpacity onPress={() => removeUrl(idx)} style={imgStyles.removeBtn} activeOpacity={0.7}>
                <Text style={imgStyles.removeText}>✕</Text>
              </TouchableOpacity>
            </View>
          ))}
        </View>
      )}
      <View style={styles.field}>
        <FieldLabel text="Add Image URL" />
        <View style={styles.row}>
          <TextInput
            style={[styles.input, { flex: 1 }]}
            placeholder="https://example.com/photo.jpg"
            placeholderTextColor={colors.placeholderColor}
            value={urlInput}
            onChangeText={setUrlInput}
            autoCapitalize="none"
            keyboardType="url"
          />
          <TouchableOpacity style={imgStyles.addUrlBtn} onPress={addUrl} activeOpacity={0.8}>
            <Text style={imgStyles.addUrlText}>Add</Text>
          </TouchableOpacity>
        </View>
      </View>
      <TouchableOpacity
        style={[imgStyles.pickBtn, uploading && styles.saveBtnDisabled]}
        onPress={pickAndUpload}
        activeOpacity={0.8}
        disabled={uploading}
      >
        {uploading
          ? <ActivityIndicator color="#fff" size="small" />
          : <Text style={imgStyles.pickBtnText}>📷  Pick from Camera Roll</Text>
        }
      </TouchableOpacity>
      <View style={styles.field}>
        <FieldLabel text="Rotation Interval (seconds)" />
        <TextInput style={styles.input} placeholder="10" placeholderTextColor={colors.placeholderColor} value={form.image_interval} onChangeText={(v) => onChange("image_interval", v)} keyboardType="numeric" />
      </View>
      <View style={styles.field}>
        <FieldLabel text="Image Fit" />
        <View style={styles.segRow}>
          {(["cover", "contain"] as const).map((fit) => (
            <TouchableOpacity
              key={fit}
              style={[styles.segBtn, form.image_fit === fit && styles.segBtnActive]}
              onPress={() => onChange("image_fit", fit)}
              activeOpacity={0.75}
            >
              <Text style={[styles.segBtnText, form.image_fit === fit && styles.segBtnTextActive]}>
                {fit === "cover" ? "Fill (Cover)" : "Fit (Contain)"}
              </Text>
            </TouchableOpacity>
          ))}
        </View>
      </View>
    </>
  );
}

const imgStyles = StyleSheet.create({
  urlRow: { flexDirection: "row", alignItems: "center", backgroundColor: colors.surfaceElevated, borderRadius: 8, paddingHorizontal: 12, paddingVertical: 8, gap: 8 },
  urlText: { flex: 1, fontSize: 12, color: colors.textSecondary, fontFamily: "monospace" },
  removeBtn: { padding: 4 },
  removeText: { fontSize: 14, color: colors.dangerText },
  addUrlBtn: { backgroundColor: colors.accent, borderRadius: 10, paddingHorizontal: 14, paddingVertical: 11, justifyContent: "center" },
  addUrlText: { fontSize: 15, fontWeight: "600", color: "#fff" },
  pickBtn: { backgroundColor: colors.surfaceElevated, borderRadius: 12, borderWidth: 1, borderColor: colors.border, paddingVertical: 12, alignItems: "center" },
  pickBtnText: { fontSize: 15, fontWeight: "500", color: colors.textPrimary },
});

// ─── Full form view ───────────────────────────────────────────────────────────

interface FormViewProps {
  form: FormState;
  onChange: (key: keyof FormState, value: string) => void;
  onBoolChange: (key: keyof FormState, value: boolean) => void;
  onLayoutChange: (gridCol: number, gridRow: number, colSpan: number, rowSpan: number) => void;
  onTypeChange: (t: CardType) => void;
  onUrlsChange: (urls: string[]) => void;
  onSave: () => void;
  onCancel: () => void;
  saving: boolean;
  isEdit: boolean;
  otherLayouts: Array<{ name: string; layout: CardLayout }>;
}

function FormView({ form, onChange, onBoolChange, onLayoutChange, onTypeChange, onUrlsChange, onSave, onCancel, saving, isEdit, otherLayouts }: FormViewProps) {
  const showDisplayOptions = form.type !== "image_rotator";
  return (
    <View style={styles.container}>
      <View style={styles.header}>
        <TouchableOpacity onPress={onCancel} style={styles.backBtn} activeOpacity={0.7}>
          <Text style={styles.backBtnText}>← Back</Text>
        </TouchableOpacity>
        <Text style={styles.title}>{isEdit ? "Edit Widget" : "New Widget"}</Text>
      </View>
      <ScrollView style={styles.scrollArea} contentContainerStyle={styles.scrollContent} keyboardShouldPersistTaps="handled">
        <SectionLabel text="Widget Type" />
        <TypeSelector selected={form.type} disabled={isEdit} onSelect={onTypeChange} />
        {isEdit && <Text style={styles.hint}>Type cannot be changed after creation.</Text>}

        <SectionLabel text="General" />
        <View style={styles.field}>
          <FieldLabel text="Name *" />
          <TextInput style={styles.input} placeholder="My Widget" placeholderTextColor={colors.placeholderColor} value={form.name} onChangeText={(v) => onChange("name", v)} />
        </View>

        <SectionLabel text={form.type === "custom_json" ? "Data Source" : form.type === "static_text" ? "Content" : form.type === "clock" ? "Clock Settings" : "Images"} />
        {form.type === "custom_json" && <CustomJsonFields form={form} onChange={onChange} />}
        {form.type === "static_text" && <StaticTextFields form={form} onChange={onChange} />}
        {form.type === "clock" && <ClockFields form={form} onChange={onChange} onBoolChange={onBoolChange} />}
        {form.type === "image_rotator" && <ImageRotatorFields form={form} onChange={onChange} onUrlsChange={onUrlsChange} />}

        {showDisplayOptions && (
          <>
            <SectionLabel text="Display" />
            <View style={styles.row}>
              <View style={[styles.field, styles.flex1]}>
                <FieldLabel text="Font Size" />
                <TextInput style={styles.input} placeholder={form.type === "clock" ? "48" : "16"} placeholderTextColor={colors.placeholderColor} value={form.font_size} onChangeText={(v) => onChange("font_size", v)} keyboardType="numeric" />
              </View>
              <View style={[styles.field, styles.flex1]}>
                <FieldLabel text="Text Color (hex)" />
                <TextInput style={styles.input} placeholder="#ffffff" placeholderTextColor={colors.placeholderColor} value={form.text_color} onChangeText={(v) => onChange("text_color", v)} autoCapitalize="none" />
              </View>
            </View>
          </>
        )}

        <SectionLabel text="Layout" />
        <View style={styles.field}>
          <Text style={styles.hint}>Tap top-left then bottom-right to place the widget on the 4Ã—4 TV grid.</Text>
          <GridPicker gridCol={form.grid_col} gridRow={form.grid_row} colSpan={form.col_span} rowSpan={form.row_span} otherLayouts={otherLayouts} onChange={onLayoutChange} />
        </View>

        <TouchableOpacity style={[styles.saveBtn, saving && styles.saveBtnDisabled]} onPress={onSave} activeOpacity={0.8} disabled={saving}>
          {saving ? <ActivityIndicator color="#fff" /> : <Text style={styles.saveBtnText}>{isEdit ? "Save Changes" : "Add Widget"}</Text>}
        </TouchableOpacity>
        <View style={{ height: 40 }} />
      </ScrollView>
    </View>
  );
}

// ─── Card List Item ───────────────────────────────────────────────────────────

const CARD_TYPE_ICONS: Record<CardType, string> = {
  custom_json: "⚡",
  static_text: "📝",
  clock: "🕐",
  image_rotator: "🖼",
};

function cardSubtitle(card: DataCard): string {
  if (card.type === "static_text") return card.config.text.slice(0, 80) || "(empty)";
  if (card.type === "clock") {
    const c = card.config;
    if (c.mode === "timer") return `Countdown → ${c.target_iso ?? "?"}`;
    return `Live time · ${c.timezone ?? "local"}`;
  }
  if (card.type === "image_rotator") return `${card.config.images.length} image(s) · ${card.config.interval}s rotation`;
  return (card as CustomJsonCard).config.url;
}

function cardMeta(card: DataCard): string {
  if (card.type === "custom_json") return `Refresh: ${(card as CustomJsonCard).config.refresh_interval}s`;
  if (card.type === "image_rotator") return `Fit: ${card.config.fit}`;
  if (card.type === "clock") return card.config.mode === "time" ? "Mode: live time" : "Mode: countdown";
  return "";
}

interface CardItemProps {
  card: DataCard;
  onEdit: () => void;
  onDelete: () => void;
  onDuplicate: () => void;
}

function CardItem({ card, onEdit, onDelete, onDuplicate }: CardItemProps) {
  return (
    <View style={styles.cardItem}>
      <View style={styles.cardItemBody}>
        <View style={{ flexDirection: "row", gap: 8, alignItems: "center" }}>
          <Text style={{ fontSize: 18 }}>{CARD_TYPE_ICONS[card.type]}</Text>
          <Text style={styles.cardItemName}>{card.name}</Text>
        </View>
        <Text style={styles.cardItemUrl} numberOfLines={2}>{cardSubtitle(card)}</Text>
        {cardMeta(card) ? <Text style={styles.cardItemMeta}>{cardMeta(card)}</Text> : null}
      </View>
      <View style={styles.cardItemActions}>
        <TouchableOpacity style={styles.editBtn} onPress={onEdit} activeOpacity={0.7}>
          <Text style={styles.editBtnText}>Edit</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.duplicateBtn} onPress={onDuplicate} activeOpacity={0.7}>
          <Text style={styles.duplicateBtnText}>Duplicate</Text>
        </TouchableOpacity>
        <TouchableOpacity style={styles.deleteBtn} onPress={onDelete} activeOpacity={0.7}>
          <Text style={styles.deleteBtnText}>Delete</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
}

// ─── Main Page ────────────────────────────────────────────────────────────────

type PageView = "list" | "form";

export function DataCardsPage() {
  const { navigate } = useRouter();
  const [pageView, setPageView] = useState<PageView>("list");
  const [cards, setCards] = useState<DataCard[]>([]);
  const [loading, setLoading] = useState(true);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [form, setForm] = useState<FormState>(EMPTY_FORM);
  const [saving, setSaving] = useState(false);

  useEffect(() => { loadCards(); }, []);

  const loadCards = () => {
    setLoading(true);
    fetch(`${BASE_URL}/pull_data_cards`)
      .then((r) => r.json())
      .then((data) => setCards(data.data_cards ?? []))
      .catch(() => Alert.alert("Error", "Failed to load widgets."))
      .finally(() => setLoading(false));
  };

  const handleAdd = () => { setEditingId(null); setForm(EMPTY_FORM); setPageView("form"); };
  const handleEdit = (card: DataCard) => { setEditingId(card.id); setForm(cardToForm(card)); setPageView("form"); };

  const handleDuplicate = (card: DataCard) => {
    const duplicate: DataCard = { ...card, id: genId(), name: `Copy of ${card.name}` } as DataCard;
    fetch(`${BASE_URL}/push_data_card`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ card: duplicate }) })
      .then((r) => r.json())
      .then((data) => { if (data.status !== "success") throw new Error(data.message); setCards((prev) => [...prev, duplicate]); })
      .catch(() => Alert.alert("Error", "Failed to duplicate widget."));
  };

  const handleDelete = (card: DataCard) => {
    Alert.alert("Delete Widget", `Remove "${card.name}"? This cannot be undone.`, [
      { text: "Cancel", style: "cancel" },
      { text: "Delete", style: "destructive", onPress: () => {
        fetch(`${BASE_URL}/push_delete_data_card`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id: card.id }) })
          .then((r) => r.json())
          .then((data) => { if (data.status !== "success") throw new Error(data.message); setCards((prev) => prev.filter((c) => c.id !== card.id)); })
          .catch(() => Alert.alert("Error", "Failed to delete widget."));
      }},
    ]);
  };

  const handleFormChange = (key: keyof FormState, value: string) => setForm((prev) => ({ ...prev, [key]: value } as FormState));
  const handleBoolChange = (key: keyof FormState, value: boolean) => setForm((prev) => ({ ...prev, [key]: value } as FormState));
  const handleLayoutChange = (gridCol: number, gridRow: number, colSpan: number, rowSpan: number) =>
    setForm((prev) => ({ ...prev, grid_col: gridCol, grid_row: gridRow, col_span: colSpan, row_span: rowSpan }));
  const handleTypeChange = (t: CardType) => setForm((prev) => ({ ...EMPTY_FORM, type: t, name: prev.name }));
  const handleUrlsChange = (urls: string[]) => setForm((prev) => ({ ...prev, image_urls: urls }));

  const handleSave = () => {
    if (!form.name.trim()) { Alert.alert("Validation", "Please enter a name."); return; }
    if (form.type === "custom_json" && !form.url.trim()) { Alert.alert("Validation", "Please enter a URL."); return; }
    if (form.type === "static_text" && !form.static_text.trim()) { Alert.alert("Validation", "Please enter some text."); return; }
    if (form.type === "clock" && form.clock_mode === "timer" && !form.clock_target_iso.trim()) { Alert.alert("Validation", "Please enter a target date/time."); return; }
    if (form.type === "image_rotator" && form.image_urls.length === 0) { Alert.alert("Validation", "Please add at least one image."); return; }

    const id = editingId ?? genId();
    const card = formToCard(form, id);
    setSaving(true);
    fetch(`${BASE_URL}/push_data_card`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ card }) })
      .then((r) => r.json())
      .then((data) => {
        if (data.status !== "success") throw new Error(data.message);
        if (editingId) { setCards((prev) => prev.map((c) => (c.id === editingId ? card : c))); }
        else { setCards((prev) => [...prev, card]); }
        setPageView("list");
      })
      .catch(() => Alert.alert("Error", "Failed to save widget."))
      .finally(() => setSaving(false));
  };

  if (pageView === "form") {
    const otherLayouts = cards
      .filter((c) => c.id !== editingId && c.layout)
      .map((c) => ({ name: c.name, layout: c.layout! }));
    return (
      <FormView
        form={form}
        onChange={handleFormChange}
        onBoolChange={handleBoolChange}
        onLayoutChange={handleLayoutChange}
        onTypeChange={handleTypeChange}
        onUrlsChange={handleUrlsChange}
        onSave={handleSave}
        onCancel={() => setPageView("list")}
        saving={saving}
        isEdit={editingId !== null}
        otherLayouts={otherLayouts}
      />
    );
  }

  return (
    <View style={styles.container}>
      <View style={styles.header}>
        <TouchableOpacity onPress={() => navigate("home")} style={styles.backBtn} activeOpacity={0.7}>
          <Text style={styles.backBtnText}>← Back</Text>
        </TouchableOpacity>
        <Text style={styles.title}>Data Cards</Text>
      </View>
      <Text style={styles.subtitle}>Widgets shown on the TV display.</Text>
      {loading ? (
        <ActivityIndicator size="large" style={{ marginTop: 32 }} />
      ) : (
        <ScrollView style={styles.scrollArea} contentContainerStyle={styles.scrollContent}>
          {cards.length === 0 && (
            <View style={styles.emptyState}>
              <Text style={styles.emptyIcon}>ðŸ“­</Text>
              <Text style={styles.emptyTitle}>No widgets yet</Text>
              <Text style={styles.emptyDesc}>Add your first widget – JSON feed, text, clock, or slideshow.</Text>
            </View>
          )}
          {cards.map((card) => (
            <CardItem key={card.id} card={card} onEdit={() => handleEdit(card)} onDelete={() => handleDelete(card)} onDuplicate={() => handleDuplicate(card)} />
          ))}
          <TouchableOpacity style={styles.addBtn} onPress={handleAdd} activeOpacity={0.8}>
            <Text style={styles.addBtnText}>+ Add Widget</Text>
          </TouchableOpacity>
          <View style={{ height: 24 }} />
        </ScrollView>
      )}
    </View>
  );
}

// ─── Styles ───────────────────────────────────────────────────────────────────

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: colors.bg },
  header: { paddingTop: 16, paddingHorizontal: 24, paddingBottom: 4, gap: 4 },
  backBtn: { alignSelf: "flex-start", paddingVertical: 4 },
  backBtnText: { fontSize: 14, color: colors.accent, fontWeight: "500" },
  title: { fontSize: 26, fontWeight: "700", color: colors.textPrimary, marginTop: 4 },
  subtitle: { fontSize: 14, color: colors.textSecondary, paddingHorizontal: 24, marginBottom: 12 },
  scrollArea: { flex: 1 },
  scrollContent: { paddingHorizontal: 24, gap: 12, paddingTop: 4 },
  emptyState: { alignItems: "center", paddingVertical: 48, gap: 8 },
  emptyIcon: { fontSize: 40 },
  emptyTitle: { fontSize: 17, fontWeight: "600", color: colors.textSecondary },
  emptyDesc: { fontSize: 14, color: colors.textMuted, textAlign: "center", maxWidth: 260 },
  cardItem: { backgroundColor: colors.surface, borderRadius: 14, borderWidth: 1, borderColor: colors.border, padding: 16, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.3, shadowRadius: 4, elevation: 3, gap: 10 },
  cardItemBody: { gap: 3 },
  cardItemName: { fontSize: 16, fontWeight: "600", color: colors.textPrimary },
  cardItemUrl: { fontSize: 12, color: colors.textSecondary, fontFamily: "monospace" },
  cardItemMeta: { fontSize: 12, color: colors.textMuted },
  cardItemActions: { flexDirection: "row", gap: 8 },
  editBtn: { flex: 1, paddingVertical: 8, borderRadius: 8, backgroundColor: colors.surfaceElevated, alignItems: "center", borderWidth: 1, borderColor: colors.border },
  editBtnText: { fontSize: 14, fontWeight: "500", color: colors.textPrimary },
  duplicateBtn: { flex: 1, paddingVertical: 8, borderRadius: 8, backgroundColor: colors.surfaceElevated, alignItems: "center", borderWidth: 1, borderColor: colors.accent + "66" },
  duplicateBtnText: { fontSize: 14, fontWeight: "500", color: colors.accent },
  deleteBtn: { flex: 1, paddingVertical: 8, borderRadius: 8, backgroundColor: colors.dangerBg, alignItems: "center", borderWidth: 1, borderColor: colors.dangerBorder },
  deleteBtnText: { fontSize: 14, fontWeight: "500", color: colors.dangerText },
  addBtn: { backgroundColor: colors.accent, borderRadius: 14, paddingVertical: 14, alignItems: "center", marginTop: 4 },
  addBtnText: { fontSize: 16, fontWeight: "600", color: "#fff" },
  sectionLabel: { fontSize: 11, fontWeight: "700", color: colors.textMuted, textTransform: "uppercase", letterSpacing: 1.2, marginTop: 8, marginBottom: -4 },
  field: { gap: 6 },
  label: { fontSize: 13, fontWeight: "600", color: colors.textMuted, textTransform: "uppercase", letterSpacing: 0.6 },
  hint: { fontSize: 12, color: colors.textMuted, lineHeight: 17 },
  code: { fontFamily: "monospace", fontSize: 12, color: colors.accent },
  input: { backgroundColor: colors.surface, borderRadius: 10, borderWidth: 1, borderColor: colors.border, paddingHorizontal: 14, paddingVertical: 11, fontSize: 15, color: colors.textPrimary },
  multilineInput: { minHeight: 80, textAlignVertical: "top", paddingTop: 10 },
  row: { flexDirection: "row", gap: 12 },
  flex1: { flex: 1 },
  saveBtn: { backgroundColor: colors.accent, borderRadius: 14, paddingVertical: 14, alignItems: "center", marginTop: 8 },
  saveBtnDisabled: { opacity: 0.45 },
  saveBtnText: { fontSize: 16, fontWeight: "600", color: "#fff" },
  segRow: { flexDirection: "row", gap: 8 },
  segBtn: { flex: 1, paddingVertical: 10, borderRadius: 10, borderWidth: 1, borderColor: colors.border, backgroundColor: colors.surface, alignItems: "center" },
  segBtnActive: { borderColor: colors.accent, backgroundColor: colors.accent + "22" },
  segBtnText: { fontSize: 14, fontWeight: "500", color: colors.textSecondary },
  segBtnTextActive: { color: colors.accent, fontWeight: "600" },
  datePickerBtn: { borderWidth: 1, borderColor: colors.border, borderRadius: 12, paddingVertical: 13, paddingHorizontal: 14, backgroundColor: colors.surface },
  datePickerBtnText: { fontSize: 15, color: colors.textPrimary },
  iosPickerOverlay: { flex: 1, justifyContent: "flex-end", backgroundColor: "rgba(0,0,0,0.45)" },
  iosPickerSheet: { backgroundColor: colors.surface, borderTopLeftRadius: 20, borderTopRightRadius: 20, paddingBottom: 32 },
  iosPickerHeader: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingHorizontal: 20, paddingVertical: 14, borderBottomWidth: 1, borderBottomColor: colors.border },
});
