/**
 * S10. Territories (pushed screen) — MAPMAP-NAV-UI-SPEC.md.
 *
 * Installed offline maps: name/version/size, Active badge, check-for-
 * updates, delete (confirm), add territory (reuses the S2c picker via the
 * `onAddTerritory` callback — the picker itself is owned by the onboarding
 * screens, not this file). Reached from Settings or the S3 offline badge
 * chip; react-navigation supplies the pushed header/title.
 *
 * Update-check contract note (see FINDINGS.md / task report): `onCheckUpdate`
 * is `(territoryId: string) => void` — fire-and-forget, no promise, no
 * delta-size or error payload. This screen cannot fabricate a delta size or
 * a genuine failure state from that alone, so it infers outcome from the
 * one real signal available — whether `installed[].version` for that
 * territory changes after the call — and times out back to idle otherwise.
 * A true "update-check failure" card can't be shown honestly until the
 * contract carries a result/error channel.
 */
import React, { useEffect, useRef, useState } from "react";
import { ActivityIndicator, Alert, StyleSheet, Text, View } from "react-native";
import { Button, Card, Chip } from "../../components";
import { radius, spacing, theme, typeScale } from "../../theme";
import type { TerritoryInfo } from "../../state/types";

export type TerritoriesScreenProps = {
  installed: TerritoryInfo[];
  storageUsedBytes: number;
  onCheckUpdate: (territoryId: string) => void;
  onDelete: (territoryId: string) => void;
  onAddTerritory: () => void;
  onSetActive: (territoryId: string) => void;
};

const CHECK_TIMEOUT_MS = 4000;
const STORAGE_BAR_TONES = [theme.signal, theme.signalPressed, theme.signalMuted];

function formatBytes(bytes: number): string {
  if (bytes <= 0) return "0 MB";
  const units = ["B", "KB", "MB", "GB"];
  let value = bytes;
  let unitIndex = 0;
  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024;
    unitIndex += 1;
  }
  const decimals = unitIndex === 0 || value >= 100 ? 0 : 1;
  return `${value.toFixed(decimals)} ${units[unitIndex]}`;
}

export function TerritoriesScreen({
  installed,
  storageUsedBytes,
  onCheckUpdate,
  onDelete,
  onAddTerritory,
  onSetActive,
}: TerritoriesScreenProps): React.JSX.Element {
  const [checkingId, setCheckingId] = useState<string | null>(null);
  const checkStartVersions = useRef<Map<string, string>>(new Map());
  const checkTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);

  const clearCheck = (): void => {
    if (checkTimeout.current) clearTimeout(checkTimeout.current);
    checkTimeout.current = null;
    setCheckingId(null);
  };

  // The only real completion signal available: the checked territory's
  // version prop changing. If it doesn't within CHECK_TIMEOUT_MS, fall
  // back to idle — see the contract note in the module doc above.
  useEffect(() => {
    if (!checkingId) return;
    const current = installed.find((t) => t.id === checkingId);
    const startVersion = checkStartVersions.current.get(checkingId);
    if (current && startVersion !== undefined && current.version !== startVersion) {
      clearCheck();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [installed, checkingId]);

  useEffect(() => () => clearCheck(), []);

  const handleCheckUpdate = (territory: TerritoryInfo): void => {
    checkStartVersions.current.set(territory.id, territory.version);
    setCheckingId(territory.id);
    onCheckUpdate(territory.id);
    if (checkTimeout.current) clearTimeout(checkTimeout.current);
    checkTimeout.current = setTimeout(clearCheck, CHECK_TIMEOUT_MS);
  };

  const handleDelete = (territory: TerritoryInfo): void => {
    Alert.alert(
      `Delete ${territory.name}?`,
      "You'll need to download it again to navigate offline in this region.",
      [
        { text: "Cancel", style: "cancel" },
        {
          text: "Delete",
          style: "destructive",
          onPress: () => onDelete(territory.id),
        },
      ]
    );
  };

  return (
    <View style={styles.container} testID="territories-screen">
      <View style={styles.content}>
        {installed.length > 0 ? (
          <StorageSummary installed={installed} storageUsedBytes={storageUsedBytes} />
        ) : null}

        {installed.length === 0 ? (
          <Card style={styles.emptyCard} testID="territories-empty">
            <Text style={styles.emptyTitle}>No territories installed</Text>
            <Text style={styles.emptyBody}>
              Add a territory to navigate offline in that region — search and
              routing both work entirely on-device once it's installed.
            </Text>
            <Button
              label="Add territory"
              onPress={onAddTerritory}
              testID="territories-add-empty"
            />
          </Card>
        ) : (
          <View style={styles.list}>
            {installed.map((territory) => (
              <TerritoryCard
                key={territory.id}
                territory={territory}
                isChecking={checkingId === territory.id}
                onCheckUpdate={() => handleCheckUpdate(territory)}
                onDelete={() => handleDelete(territory)}
                onSetActive={() => onSetActive(territory.id)}
              />
            ))}
            <Button
              label="Add another territory"
              variant="secondary"
              fullWidth
              onPress={onAddTerritory}
              testID="territories-add-more"
            />
          </View>
        )}
      </View>
    </View>
  );
}

/* ================= internal building blocks ================= */

function StorageSummary({
  installed,
  storageUsedBytes,
}: {
  installed: TerritoryInfo[];
  storageUsedBytes: number;
}): React.JSX.Element {
  return (
    <Card testID="territories-storage-summary">
      <Text style={styles.storageTitle}>Storage</Text>
      <View style={styles.storageBar}>
        {installed.map((territory, index) => (
          <View
            key={territory.id}
            style={{
              flex: Math.max(territory.sizeOnDiskBytes, 1),
              backgroundColor: STORAGE_BAR_TONES[index % STORAGE_BAR_TONES.length],
            }}
          />
        ))}
      </View>
      <Text style={styles.storageCaption}>
        {formatBytes(storageUsedBytes)} used across{" "}
        {installed.length} {installed.length === 1 ? "territory" : "territories"}
      </Text>
    </Card>
  );
}

function TerritoryCard({
  territory,
  isChecking,
  onCheckUpdate,
  onDelete,
  onSetActive,
}: {
  territory: TerritoryInfo;
  isChecking: boolean;
  onCheckUpdate: () => void;
  onDelete: () => void;
  onSetActive: () => void;
}): React.JSX.Element {
  return (
    <Card testID={`territory-card-${territory.id}`}>
      <View style={styles.territoryHeader}>
        <View style={styles.territoryNameColumn}>
          <Text style={styles.territoryName} numberOfLines={1}>
            {territory.name}
          </Text>
          <Text style={styles.territoryMeta}>
            v{territory.version} · {formatBytes(territory.sizeOnDiskBytes)}
          </Text>
        </View>
        {territory.active ? (
          <Chip label="Active" tone="signal" testID={`territory-active-${territory.id}`} />
        ) : (
          <Button
            label="Set active"
            variant="secondary"
            onPress={onSetActive}
            testID={`territory-set-active-${territory.id}`}
          />
        )}
      </View>

      {isChecking ? (
        <View style={styles.checkingRow}>
          <ActivityIndicator size="small" color={theme.textSecondary} />
          <Text style={styles.checkingText}>Checking for updates…</Text>
        </View>
      ) : null}

      <View style={styles.territoryActions}>
        <Button
          label="Check for updates"
          variant="secondary"
          onPress={onCheckUpdate}
          disabled={isChecking}
          testID={`territory-check-${territory.id}`}
        />
        <Button
          label="Delete"
          variant="destructive"
          onPress={onDelete}
          testID={`territory-delete-${territory.id}`}
        />
      </View>
    </Card>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: theme.background,
  },
  content: {
    padding: spacing[4],
    gap: spacing[4],
  },
  list: {
    gap: spacing[4],
  },
  storageTitle: {
    fontSize: typeScale.label.fontSize,
    fontWeight: typeScale.label.fontWeight,
    color: theme.textPrimary,
    marginBottom: spacing[3],
  },
  storageBar: {
    flexDirection: "row",
    height: 8,
    borderRadius: radius.pill,
    overflow: "hidden",
    backgroundColor: theme.surfaceAlt,
  },
  storageCaption: {
    marginTop: spacing[2],
    fontSize: typeScale.caption.fontSize,
    color: theme.textSecondary,
  },
  emptyCard: {
    alignItems: "flex-start",
    gap: spacing[3],
  },
  emptyTitle: {
    fontSize: typeScale.headline.fontSize,
    fontWeight: typeScale.headline.fontWeight,
    color: theme.textPrimary,
  },
  emptyBody: {
    fontSize: typeScale.body.fontSize,
    color: theme.textSecondary,
    lineHeight: typeScale.body.lineHeight,
  },
  territoryHeader: {
    flexDirection: "row",
    alignItems: "flex-start",
    justifyContent: "space-between",
    gap: spacing[3],
  },
  territoryNameColumn: {
    flex: 1,
  },
  territoryName: {
    fontSize: typeScale.headline.fontSize,
    fontWeight: typeScale.headline.fontWeight,
    color: theme.textPrimary,
  },
  territoryMeta: {
    marginTop: 2,
    fontSize: typeScale.caption.fontSize,
    color: theme.textSecondary,
  },
  checkingRow: {
    flexDirection: "row",
    alignItems: "center",
    gap: spacing[2],
    marginTop: spacing[3],
  },
  checkingText: {
    fontSize: typeScale.caption.fontSize,
    color: theme.textSecondary,
  },
  territoryActions: {
    flexDirection: "row",
    gap: spacing[3],
    marginTop: spacing[4],
  },
});
