import { Ionicons } from "@expo/vector-icons";
import React, { useCallback, useEffect, useRef, useState } from "react";
import {
  ActivityIndicator,
  Animated,
  Dimensions,
  Keyboard,
  Modal,
  Platform,
  Pressable,
  ScrollView,
  StyleSheet,
  Text,
  TextInput,
  View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import QRCode from "react-native-qrcode-svg";

import { Colors } from "@/constants/colors";

const C = Colors.dark;
const POLL_INTERVAL = 3000;
const SCREEN_WIDTH = Dimensions.get("window").width;
const QR_SIZE = Math.min(SCREEN_WIDTH - 80, 240);

const BASE_URL = process.env.EXPO_PUBLIC_DOMAIN ?? "";

function getApiBase(): string {
  let domain = BASE_URL;
  if (!domain) domain = "localhost:8080";
  domain = domain.replace(/\/$/, "");
  if (!/^https?:\/\//.test(domain)) {
    const proto = domain.startsWith("localhost") ? "http" : "https";
    domain = `${proto}://${domain}`;
  }
  return domain;
}

type JobState =
  | "awaiting_eval_payment"
  | "evaluating"
  | "rejected"
  | "awaiting_work_payment"
  | "executing"
  | "complete"
  | "failed";

type InvoiceInfo = {
  paymentRequest: string;
  amountSats: number;
};

type JobStatus = {
  jobId: string;
  state: JobState;
  evalInvoice?: InvoiceInfo;
  workInvoice?: InvoiceInfo;
  result?: string;
  reason?: string;
  errorMessage?: string;
};

type CreateJobResponse = {
  jobId: string;
  evalInvoice: InvoiceInfo;
};

type EstimateResponse = {
  estimatedCostSats: number;
  estimatedCostUsd: number;
  btcPriceUsd: number;
};

const STATE_LABELS: Record<string, string> = {
  awaiting_eval_payment: "Awaiting eval payment",
  evaluating: "Evaluating your request...",
  rejected: "Request rejected",
  awaiting_work_payment: "Awaiting work payment",
  executing: "Executing job...",
  complete: "Complete!",
  failed: "Job failed",
};

const STATE_ICONS: Record<string, string> = {
  awaiting_eval_payment: "flash-outline",
  evaluating: "hourglass-outline",
  rejected: "close-circle-outline",
  awaiting_work_payment: "flash-outline",
  executing: "cog-outline",
  complete: "checkmark-circle-outline",
  failed: "alert-circle-outline",
};

type Props = {
  visible: boolean;
  onClose: () => void;
};

export function JobSubmissionSheet({ visible, onClose }: Props) {
  const insets = useSafeAreaInsets();
  const [prompt, setPrompt] = useState("");
  const [estimate, setEstimate] = useState<EstimateResponse | null>(null);
  const [estimateLoading, setEstimateLoading] = useState(false);
  const [estimateError, setEstimateError] = useState("");
  const [jobId, setJobId] = useState<string | null>(null);
  const [jobStatus, setJobStatus] = useState<JobStatus | null>(null);
  const [submitting, setSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState("");
  const [resultExpanded, setResultExpanded] = useState(false);
  const slideAnim = useRef(new Animated.Value(0)).current;
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  // Slide animation
  useEffect(() => {
    Animated.timing(slideAnim, {
      toValue: visible ? 1 : 0,
      duration: 300,
      useNativeDriver: true,
    }).start();
  }, [visible, slideAnim]);

  // Polling for job status
  useEffect(() => {
    if (!jobId) return;

    const poll = async () => {
      try {
        const res = await fetch(`${getApiBase()}/api/jobs/${jobId}`);
        if (!res.ok) return;
        const data = (await res.json()) as JobStatus;
        setJobStatus(data);

        // Stop polling on terminal states
        if (
          data.state === "complete" ||
          data.state === "failed" ||
          data.state === "rejected"
        ) {
          if (pollRef.current) {
            clearInterval(pollRef.current);
            pollRef.current = null;
          }
        }
      } catch {
        // ignore poll errors
      }
    };

    // Immediately fetch once
    void poll();
    pollRef.current = setInterval(poll, POLL_INTERVAL);

    return () => {
      if (pollRef.current) {
        clearInterval(pollRef.current);
        pollRef.current = null;
      }
    };
  }, [jobId]);

  const resetState = useCallback(() => {
    setPrompt("");
    setEstimate(null);
    setEstimateError("");
    setJobId(null);
    setJobStatus(null);
    setSubmitting(false);
    setSubmitError("");
    setResultExpanded(false);
    if (pollRef.current) {
      clearInterval(pollRef.current);
      pollRef.current = null;
    }
  }, []);

  const handleClose = useCallback(() => {
    resetState();
    onClose();
  }, [onClose, resetState]);

  const handleEstimate = useCallback(async () => {
    if (!prompt.trim()) return;
    Keyboard.dismiss();
    setEstimateLoading(true);
    setEstimateError("");
    setEstimate(null);
    try {
      const res = await fetch(`${getApiBase()}/api/jobs/estimate`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request: prompt.trim() }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: "Request failed" }));
        setEstimateError(
          (err as { error?: string }).error ?? `HTTP ${res.status}`
        );
        return;
      }
      const data = (await res.json()) as EstimateResponse;
      setEstimate(data);
    } catch (e) {
      setEstimateError(
        e instanceof Error ? e.message : "Failed to get estimate"
      );
    } finally {
      setEstimateLoading(false);
    }
  }, [prompt]);

  const handleSubmit = useCallback(async () => {
    if (!prompt.trim()) return;
    Keyboard.dismiss();
    setSubmitting(true);
    setSubmitError("");
    try {
      const res = await fetch(`${getApiBase()}/api/jobs`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ request: prompt.trim() }),
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: "Request failed" }));
        setSubmitError(
          (err as { error?: string }).error ?? `HTTP ${res.status}`
        );
        return;
      }
      const data = (await res.json()) as CreateJobResponse;
      setJobId(data.jobId);
      setJobStatus({
        jobId: data.jobId,
        state: "awaiting_eval_payment",
        evalInvoice: data.evalInvoice,
      });
    } catch (e) {
      setSubmitError(
        e instanceof Error ? e.message : "Failed to submit job"
      );
    } finally {
      setSubmitting(false);
    }
  }, [prompt]);

  // Determine which invoice to show
  const activeInvoice: InvoiceInfo | undefined =
    jobStatus?.state === "awaiting_work_payment"
      ? jobStatus.workInvoice
      : jobStatus?.state === "awaiting_eval_payment"
        ? jobStatus.evalInvoice
        : undefined;

  const isTerminal =
    jobStatus?.state === "complete" ||
    jobStatus?.state === "failed" ||
    jobStatus?.state === "rejected";

  const isPolling = jobId != null && !isTerminal;

  const renderContent = () => {
    // === JOB IN PROGRESS / COMPLETE ===
    if (jobId && jobStatus) {
      return (
        <ScrollView
          style={styles.sheetScroll}
          contentContainerStyle={styles.sheetScrollContent}
          keyboardShouldPersistTaps="handled"
        >
          {/* Status badge */}
          <View style={styles.statusRow}>
            <Ionicons
              name={
                (STATE_ICONS[jobStatus.state] ?? "help-outline") as React.ComponentProps<typeof Ionicons>["name"]
              }
              size={20}
              color={
                jobStatus.state === "complete"
                  ? C.jobCompleted
                  : jobStatus.state === "failed" || jobStatus.state === "rejected"
                    ? C.error
                    : C.jobStarted
              }
            />
            <Text
              style={[
                styles.statusText,
                jobStatus.state === "complete" && { color: C.jobCompleted },
                (jobStatus.state === "failed" ||
                  jobStatus.state === "rejected") && { color: C.error },
              ]}
            >
              {STATE_LABELS[jobStatus.state] ?? jobStatus.state}
            </Text>
            {isPolling && (
              <ActivityIndicator size="small" color={C.accent} />
            )}
          </View>

          {/* Invoice QR */}
          {activeInvoice && (
            <View style={styles.qrContainer}>
              <Text style={styles.qrLabel}>
                {jobStatus.state === "awaiting_eval_payment"
                  ? "Pay eval invoice"
                  : "Pay work invoice"}
              </Text>
              <View style={styles.qrWrapper}>
                <QRCode
                  value={activeInvoice.paymentRequest}
                  size={QR_SIZE}
                  backgroundColor="#FFFFFF"
                  color="#000000"
                />
              </View>
              <Text style={styles.satsLabel}>
                {activeInvoice.amountSats} sats
              </Text>
              <Text style={styles.invoiceHint}>
                Scan with your Lightning wallet
              </Text>
            </View>
          )}

          {/* Rejection reason */}
          {jobStatus.state === "rejected" && jobStatus.reason && (
            <View style={styles.errorCard}>
              <Ionicons name="close-circle" size={16} color={C.error} />
              <Text style={styles.errorCardText}>{jobStatus.reason}</Text>
            </View>
          )}

          {/* Error message */}
          {jobStatus.state === "failed" && jobStatus.errorMessage && (
            <View style={styles.errorCard}>
              <Ionicons name="alert-circle" size={16} color={C.error} />
              <Text style={styles.errorCardText}>
                {jobStatus.errorMessage}
              </Text>
            </View>
          )}

          {/* Result */}
          {jobStatus.state === "complete" && jobStatus.result && (
            <Pressable
              style={styles.resultCard}
              onPress={() => setResultExpanded((v) => !v)}
            >
              <View style={styles.resultHeader}>
                <Ionicons
                  name="checkmark-circle"
                  size={18}
                  color={C.jobCompleted}
                />
                <Text style={styles.resultTitle}>Result</Text>
                <Ionicons
                  name={resultExpanded ? "chevron-up" : "chevron-down"}
                  size={16}
                  color={C.textSecondary}
                />
              </View>
              <Text
                style={styles.resultText}
                numberOfLines={resultExpanded ? undefined : 6}
              >
                {jobStatus.result}
              </Text>
            </Pressable>
          )}

          {/* New job button for terminal states */}
          {isTerminal && (
            <Pressable style={styles.newJobButton} onPress={resetState}>
              <Text style={styles.newJobButtonText}>Submit another job</Text>
            </Pressable>
          )}
        </ScrollView>
      );
    }

    // === INPUT FORM ===
    return (
      <ScrollView
        style={styles.sheetScroll}
        contentContainerStyle={styles.sheetScrollContent}
        keyboardShouldPersistTaps="handled"
      >
        <Text style={styles.inputLabel}>What should Timmy do?</Text>
        <TextInput
          style={styles.textInput}
          placeholder="Describe your job..."
          placeholderTextColor={C.textMuted}
          value={prompt}
          onChangeText={setPrompt}
          multiline
          numberOfLines={4}
          textAlignVertical="top"
          maxLength={2000}
          autoFocus
        />

        {/* Estimate result */}
        {estimate && (
          <View style={styles.estimateCard}>
            <Ionicons name="flash" size={16} color={C.jobStarted} />
            <Text style={styles.estimateText}>
              Estimated cost: {estimate.estimatedCostSats} sats (~$
              {estimate.estimatedCostUsd.toFixed(4)})
            </Text>
          </View>
        )}

        {estimateError ? (
          <View style={styles.errorCard}>
            <Ionicons name="alert-circle" size={16} color={C.error} />
            <Text style={styles.errorCardText}>{estimateError}</Text>
          </View>
        ) : null}

        {submitError ? (
          <View style={styles.errorCard}>
            <Ionicons name="alert-circle" size={16} color={C.error} />
            <Text style={styles.errorCardText}>{submitError}</Text>
          </View>
        ) : null}

        {/* Action buttons */}
        <View style={styles.buttonRow}>
          <Pressable
            style={[
              styles.estimateButton,
              (!prompt.trim() || estimateLoading) && styles.buttonDisabled,
            ]}
            onPress={handleEstimate}
            disabled={!prompt.trim() || estimateLoading}
          >
            {estimateLoading ? (
              <ActivityIndicator size="small" color={C.accent} />
            ) : (
              <>
                <Ionicons name="calculator-outline" size={18} color={C.accent} />
                <Text style={styles.estimateButtonText}>Estimate</Text>
              </>
            )}
          </Pressable>

          <Pressable
            style={[
              styles.submitButton,
              (!prompt.trim() || submitting) && styles.buttonDisabled,
            ]}
            onPress={handleSubmit}
            disabled={!prompt.trim() || submitting}
          >
            {submitting ? (
              <ActivityIndicator size="small" color="#fff" />
            ) : (
              <>
                <Ionicons name="flash" size={18} color="#fff" />
                <Text style={styles.submitButtonText}>Submit Job</Text>
              </>
            )}
          </Pressable>
        </View>
      </ScrollView>
    );
  };

  return (
    <Modal
      visible={visible}
      animationType="slide"
      transparent
      onRequestClose={handleClose}
    >
      <View style={styles.overlay}>
        <Pressable style={styles.overlayBackdrop} onPress={handleClose} />
        <Animated.View
          style={[
            styles.sheet,
            {
              paddingBottom: Math.max(insets.bottom, 16),
              transform: [
                {
                  translateY: slideAnim.interpolate({
                    inputRange: [0, 1],
                    outputRange: [600, 0],
                  }),
                },
              ],
            },
          ]}
        >
          {/* Handle bar */}
          <View style={styles.handleRow}>
            <View style={styles.handle} />
          </View>

          {/* Header */}
          <View style={styles.sheetHeader}>
            <Ionicons name="flash" size={22} color={C.jobStarted} />
            <Text style={styles.sheetTitle}>Submit Job</Text>
            <Pressable
              onPress={handleClose}
              hitSlop={12}
              accessibilityRole="button"
              accessibilityLabel="Close"
            >
              <Ionicons name="close" size={24} color={C.textSecondary} />
            </Pressable>
          </View>

          {renderContent()}
        </Animated.View>
      </View>
    </Modal>
  );
}

const styles = StyleSheet.create({
  overlay: {
    flex: 1,
    justifyContent: "flex-end",
  },
  overlayBackdrop: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: "rgba(0,0,0,0.5)",
  },
  sheet: {
    backgroundColor: C.surface,
    borderTopLeftRadius: 20,
    borderTopRightRadius: 20,
    maxHeight: "85%",
    borderWidth: 1,
    borderBottomWidth: 0,
    borderColor: C.border,
  },
  handleRow: {
    alignItems: "center",
    paddingTop: 10,
    paddingBottom: 4,
  },
  handle: {
    width: 36,
    height: 4,
    borderRadius: 2,
    backgroundColor: C.textMuted,
  },
  sheetHeader: {
    flexDirection: "row",
    alignItems: "center",
    paddingHorizontal: 20,
    paddingVertical: 12,
    gap: 10,
    borderBottomWidth: 1,
    borderBottomColor: C.border,
  },
  sheetTitle: {
    flex: 1,
    fontSize: 18,
    fontFamily: "Inter_600SemiBold",
    color: C.text,
  },
  sheetScroll: {
    flex: 1,
  },
  sheetScrollContent: {
    padding: 20,
    gap: 16,
  },
  inputLabel: {
    fontSize: 14,
    fontFamily: "Inter_500Medium",
    color: C.textSecondary,
  },
  textInput: {
    backgroundColor: C.surfaceElevated,
    borderRadius: 12,
    borderWidth: 1,
    borderColor: C.border,
    color: C.text,
    fontFamily: "Inter_400Regular",
    fontSize: 15,
    padding: 14,
    minHeight: 100,
    ...(Platform.OS === "web" ? { outlineStyle: "none" as unknown as undefined } : {}),
  },
  estimateCard: {
    flexDirection: "row",
    alignItems: "center",
    gap: 8,
    backgroundColor: C.surfaceElevated,
    borderRadius: 10,
    padding: 12,
    borderWidth: 1,
    borderColor: C.jobStarted + "44",
  },
  estimateText: {
    fontSize: 14,
    fontFamily: "Inter_500Medium",
    color: C.jobStarted,
    flex: 1,
  },
  errorCard: {
    flexDirection: "row",
    alignItems: "flex-start",
    gap: 8,
    backgroundColor: C.error + "18",
    borderRadius: 10,
    padding: 12,
    borderWidth: 1,
    borderColor: C.error + "44",
  },
  errorCardText: {
    fontSize: 13,
    fontFamily: "Inter_400Regular",
    color: C.error,
    flex: 1,
  },
  buttonRow: {
    flexDirection: "row",
    gap: 12,
  },
  estimateButton: {
    flex: 1,
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center",
    gap: 6,
    backgroundColor: C.surfaceElevated,
    borderRadius: 12,
    paddingVertical: 14,
    borderWidth: 1,
    borderColor: C.accent + "44",
  },
  estimateButtonText: {
    fontSize: 15,
    fontFamily: "Inter_600SemiBold",
    color: C.accent,
  },
  submitButton: {
    flex: 1,
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "center",
    gap: 6,
    backgroundColor: C.accent,
    borderRadius: 12,
    paddingVertical: 14,
  },
  submitButtonText: {
    fontSize: 15,
    fontFamily: "Inter_600SemiBold",
    color: "#fff",
  },
  buttonDisabled: {
    opacity: 0.5,
  },
  statusRow: {
    flexDirection: "row",
    alignItems: "center",
    gap: 8,
    backgroundColor: C.surfaceElevated,
    borderRadius: 10,
    padding: 12,
    borderWidth: 1,
    borderColor: C.border,
  },
  statusText: {
    flex: 1,
    fontSize: 14,
    fontFamily: "Inter_500Medium",
    color: C.text,
  },
  qrContainer: {
    alignItems: "center",
    gap: 12,
  },
  qrLabel: {
    fontSize: 14,
    fontFamily: "Inter_500Medium",
    color: C.textSecondary,
  },
  qrWrapper: {
    backgroundColor: "#FFFFFF",
    padding: 16,
    borderRadius: 12,
  },
  satsLabel: {
    fontSize: 20,
    fontFamily: "Inter_700Bold",
    color: C.jobStarted,
  },
  invoiceHint: {
    fontSize: 12,
    fontFamily: "Inter_400Regular",
    color: C.textMuted,
  },
  resultCard: {
    backgroundColor: C.surfaceElevated,
    borderRadius: 12,
    padding: 14,
    borderWidth: 1,
    borderColor: C.jobCompleted + "44",
    gap: 10,
  },
  resultHeader: {
    flexDirection: "row",
    alignItems: "center",
    gap: 8,
  },
  resultTitle: {
    flex: 1,
    fontSize: 15,
    fontFamily: "Inter_600SemiBold",
    color: C.text,
  },
  resultText: {
    fontSize: 14,
    fontFamily: "Inter_400Regular",
    color: C.text,
    lineHeight: 20,
  },
  newJobButton: {
    alignItems: "center",
    paddingVertical: 14,
    backgroundColor: C.surfaceElevated,
    borderRadius: 12,
    borderWidth: 1,
    borderColor: C.border,
  },
  newJobButtonText: {
    fontSize: 15,
    fontFamily: "Inter_500Medium",
    color: C.accent,
  },
});
