import { useEffect, useState } from "react";
import { Alert, View } from "react-native";
import { router } from "expo-router";
import * as ImagePicker from "expo-image-picker";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { api, uploadImage, ApiError } from "@/lib/api";
import { t } from "@/lib/i18n";
import {
  Body,
  Card,
  Heading,
  LoadingView,
  Row,
  Screen,
  Small,
  Spacer,
  Title,
} from "@/components/ui";
import { spacing } from "@/lib/theme";
import { useAnalytics } from "@/lib/analytics";
import { scanStarted } from "@app/analytics";
import { FirstScanCoach, useFirstScanCoach } from "@/components/FirstScanCoach";

/** Skanna (spec §4.2): kyl, frys, skafferi, ingredienser, tallrik, kvitto, streckkod.
 *  Näringsdeklaration är INGEN egen knapp – den vävs in i streckkodsflödet: okänd kod → fota
 *  förpackningen → produkten läses av och sparas i den delade katalogen (se barcode.tsx).
 *  "Bäst före datum" borttaget – fyllde ingen funktion i flödet. */

const SCAN_TYPES = [
  { type: "fridge", glyph: "🧊", labelKey: "scan.fridge" },
  { type: "freezer", glyph: "❄️", labelKey: "scan.freezer" },
  { type: "pantry", glyph: "🗄️", labelKey: "scan.pantry" },
  { type: "ingredients", glyph: "🥕", labelKey: "scan.ingredients" },
  { type: "plate", glyph: "🍽️", labelKey: "scan.plate" },
  { type: "receipt", glyph: "🧾", labelKey: "scan.receipt" },
  { type: "barcode", glyph: "🏷️", labelKey: "scan.barcode" },
] as const;

/**
 * Platser där flera bilder i EN skanning hjälper: modellen ser hela hyllan från
 * flera vinklar och listar varje vara en gång (dedup över bilder, spec §9).
 * Enkel-typer (tallrik/kvitto/datum/näringsetikett) tar en bild.
 */
const MULTI_PHOTO_TYPES = new Set(["fridge", "freezer", "pantry", "ingredients"]);
const MAX_PHOTOS = 6; // matchar createScanInputSchema.imageCount.max

/** Fråga om användaren vill ta fler bilder i samma skanning. */
function askAddMore(count: number, maxCount: number): Promise<boolean> {
  return new Promise((resolve) => {
    if (count >= maxCount) {
      Alert.alert(t("scan.maxTitle"), t("scan.maxBody", { max: maxCount }), [
        { text: "OK", onPress: () => resolve(false) },
      ]);
      return;
    }
    Alert.alert(t("scan.photoTaken", { count }), t("scan.multiAngleHint"), [
      { text: t("scan.takeAnother"), onPress: () => resolve(true) },
      { text: t("scan.analyzeCount", { count }), style: "default", onPress: () => resolve(false) },
    ]);
  });
}

/**
 * Fånga en eller flera bilder. Kamera → loop med "ta en till"; galleri → flerval.
 * maxCount kapar antalet till kvarvarande kvot (varje bild = en skanning).
 */
async function capturePhotos(multi: boolean, maxCount: number): Promise<string[]> {
  const permission = await ImagePicker.requestCameraPermissionsAsync();
  const useCamera = permission.granted;
  const uris: string[] = [];
  const cap = Math.max(1, maxCount);

  if (!multi || cap === 1) {
    const picked = useCamera
      ? await ImagePicker.launchCameraAsync({ quality: 0.7 })
      : await ImagePicker.launchImageLibraryAsync({ quality: 0.7 });
    const asset = picked.assets?.[0];
    if (!picked.canceled && asset) uris.push(asset.uri);
    return uris;
  }

  if (!useCamera) {
    // Utan kameratillstånd: låt användaren välja flera bilder ur galleriet på en gång.
    const picked = await ImagePicker.launchImageLibraryAsync({
      quality: 0.7,
      allowsMultipleSelection: true,
      selectionLimit: cap,
    });
    if (!picked.canceled) for (const a of (picked.assets ?? []).slice(0, cap)) uris.push(a.uri);
    return uris;
  }

  // Kamera: ta en bild i taget, fråga om fler mellan varje (upp till kvot-taket).
  while (uris.length < cap) {
    const picked = await ImagePicker.launchCameraAsync({ quality: 0.7 });
    const asset = picked.assets?.[0];
    if (picked.canceled || !asset) break;
    uris.push(asset.uri);
    const more = await askAddMore(uris.length, cap);
    if (!more) break;
  }
  return uris;
}

interface CreateScanResponse {
  scan: { id: string };
  uploads: Array<{ key: string; uploadUrl: string; headers: Record<string, string> }>;
}
interface Entitlements {
  aiScansPerMonth: number;
  aiScansUsedThisMonth: number;
}

export default function ScanScreen() {
  const [busyType, setBusyType] = useState<string | null>(null);
  const coach = useFirstScanCoach();
  const { track } = useAnalytics();
  const queryClient = useQueryClient();
  const entitlements = useQuery({
    queryKey: ["entitlements"],
    queryFn: () => api<Entitlements>("/v1/me/entitlements"),
  });

  useEffect(() => {
    void coach.showIfNeeded();
  }, []);

  const startScan = async (scanType: string) => {
    track(scanStarted({ properties: { scanType } }));
    if (scanType === "barcode") {
      router.push("/barcode");
      return;
    }
    try {
      // Varje bild = en skanning. Kapa antalet foton till kvarvarande kvot, och
      // skicka till paywall direkt om kvoten redan är slut (servern är dock den
      // som slutgiltigt räknar – appens tak är bara för att slippa blockering mitt i).
      const remaining = entitlements.data
        ? entitlements.data.aiScansPerMonth - entitlements.data.aiScansUsedThisMonth
        : null;
      if (remaining != null && remaining <= 0) {
        router.push("/paywall");
        return;
      }
      const cap = remaining != null ? Math.min(MAX_PHOTOS, remaining) : MAX_PHOTOS;

      // 1. Ta bild(er) – flera vinklar tillåtna för kyl/frys/skafferi/ingredienser.
      const multi = MULTI_PHOTO_TYPES.has(scanType);
      const uris = await capturePhotos(multi, cap);
      if (uris.length === 0) return; // avbruten

      // Visa laddning först nu (kamera/dialoger är egna vyer).
      setBusyType(scanType);

      // 2. Skapa jobb + presignade uploads (en per bild). Kvotkontroll i API:t;
      //    en skanning = en kvotenhet oavsett antal bilder.
      const created = await api<CreateScanResponse>("/v1/scans", {
        method: "POST",
        body: { scanType, imageCount: uris.length, contentType: "image/jpeg" },
      });
      queryClient.invalidateQueries({ queryKey: ["entitlements"] });

      // 3. Ladda upp alla bilder, starta sedan analysen.
      for (let i = 0; i < uris.length; i++) {
        const upload = created.uploads[i];
        if (!upload) throw new Error(t("common.error"));
        await uploadImage(upload, uris[i]!);
      }
      await api(`/v1/scans/${created.scan.id}/start`, { method: "POST" });

      // 4. Vidare till granskningsvyn som pollar tills resultatet kommer.
      router.push(`${scanType === "plate" ? "/meal-review" : "/scan-review"}/${created.scan.id}`);
    } catch (err) {
      if (err instanceof ApiError && err.code === "QUOTA_EXCEEDED") {
        router.push("/paywall");
      } else {
        Alert.alert(t("common.oops"), err instanceof Error ? err.message : t("common.error"));
      }
    } finally {
      setBusyType(null);
    }
  };

  const quota = entitlements.data
    ? entitlements.data.aiScansPerMonth - entitlements.data.aiScansUsedThisMonth
    : null;

  return (
    <Screen>
      <FirstScanCoach visible={coach.visible} onDismiss={coach.dismiss} />
      <Title>{t("scan.title")}</Title>
      <Small>{t("scan.subtitle")}</Small>
      {quota != null && <Small>{t("scan.quotaLeft", { count: Math.max(0, quota) })}</Small>}
      <Small>{t("scan.costNote")}</Small>
      <Spacer size={spacing.sm} />

      {busyType && <LoadingView />}

      <View style={{ flexDirection: "row", flexWrap: "wrap", gap: spacing.sm }}>
        {SCAN_TYPES.map((item) => (
          <Card
            key={item.type}
            onPress={() => void startScan(item.type)}
            style={{ width: "31%", alignItems: "center", paddingVertical: spacing.md }}
          >
            <Body>{item.glyph}</Body>
            <Small>{t(item.labelKey as never)}</Small>
          </Card>
        ))}
      </View>

      <Spacer />
      <Card>
        <Heading>{t("scan.tips.title")}</Heading>
        <Small>• {t("scan.tips.overview")}</Small>
        <Small>• {t("scan.tips.shelf")}</Small>
        <Small>• {t("scan.tips.light")}</Small>
        <Small>• {t("scan.tips.move")}</Small>
        <Small>• {t("scan.tips.merge")}</Small>
      </Card>
    </Screen>
  );
}
