"use client";

import { useEffect, useState, useCallback, useMemo } from "react";
import { useRouter } from "next/navigation";
import { Permission } from "../auth-context";
import { exchangeApi, tradesApi } from "../api";
import { extractApiErrorMessage } from "../utils/error-handling";
import { Header } from "../components/Header";
import { LoadingState } from "../components/LoadingState";
import { useRequireAuth } from "../hooks/useRequireAuth";
import { components } from "../generated/api";
import { formatDate, getDateRange } from "../utils/date";
import { layoutStyles, typographyStyles, bannerStyles } from "../styles/shared";
import constants from "../../../shared/constants.json";
import { useExchangePrice } from "./hooks/useExchangePrice";
import { useAvailableSlots } from "./hooks/useAvailableSlots";
import { PriceDisplay } from "./components/PriceDisplay";
import { StepIndicator } from "./components/StepIndicator";
import { ExchangeDetailsStep } from "./components/ExchangeDetailsStep";
import { BookingStep } from "./components/BookingStep";
import { ConfirmationStep } from "./components/ConfirmationStep";
import { useTranslation } from "../hooks/useTranslation";

type ExchangeResponse = components["schemas"]["ExchangeResponse"];

// Constants from shared config
const {
  minAdvanceDays: MIN_ADVANCE_DAYS,
  maxAdvanceDays: MAX_ADVANCE_DAYS,
  lightningMaxEur: LIGHTNING_MAX_EUR,
} = constants.exchange;

type Direction = "buy" | "sell";
type BitcoinTransferMethod = "onchain" | "lightning";
type WizardStep = "details" | "booking" | "confirmation";

const styles = {
  content: {
    flex: 1,
    padding: "2rem",
    maxWidth: "900px",
    margin: "0 auto",
    width: "100%",
  },
  errorLink: {
    marginTop: "0.75rem",
    paddingTop: "0.75rem",
    borderTop: "1px solid rgba(255, 255, 255, 0.1)",
  },
  errorLinkAnchor: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    color: "#a78bfa",
    textDecoration: "none",
    fontWeight: 500,
    fontSize: "0.9rem",
  },
} as const;

export default function ExchangePage() {
  const router = useRouter();
  const t = useTranslation("exchange");
  const { user, isLoading, isAuthorized } = useRequireAuth({
    requiredPermission: Permission.CREATE_EXCHANGE,
    fallbackRedirect: "/",
  });

  // Wizard state
  const [wizardStep, setWizardStep] = useState<WizardStep>("details");

  // Trade form state
  const [direction, setDirection] = useState<Direction>("buy");
  const [bitcoinTransferMethod, setBitcoinTransferMethod] =
    useState<BitcoinTransferMethod>("onchain");
  const [eurAmount, setEurAmount] = useState<number>(10000); // €100 in cents

  // Date/slot selection state
  const [selectedDate, setSelectedDate] = useState<Date | null>(null);
  const [selectedSlot, setSelectedSlot] = useState<components["schemas"]["BookableSlot"] | null>(
    null
  );

  // User trades state (for same-day booking check)
  const [userTrades, setUserTrades] = useState<ExchangeResponse[]>([]);
  const [existingTradeOnSelectedDate, setExistingTradeOnSelectedDate] =
    useState<ExchangeResponse | null>(null);

  // UI state
  const [error, setError] = useState<string | null>(null);
  const [existingTradeId, setExistingTradeId] = useState<string | null>(null);
  const [isBooking, setIsBooking] = useState(false);

  // Compute dates
  const dates = useMemo(() => getDateRange(MIN_ADVANCE_DAYS, MAX_ADVANCE_DAYS), []);

  // Use custom hooks for price and slots
  const {
    priceData,
    isLoading: isPriceLoading,
    error: priceError,
    lastUpdate: lastPriceUpdate,
  } = useExchangePrice({
    enabled: !!user && isAuthorized,
  });

  const {
    availableSlots,
    datesWithAvailability,
    isLoadingSlots,
    isLoadingAvailability,
    fetchSlots,
  } = useAvailableSlots({
    enabled: !!user && isAuthorized,
    dates,
    wizardStep,
  });

  // Config from API
  const config = priceData?.config;
  const eurMin = config?.eur_min ?? 100;
  const eurMax = config?.eur_max ?? 3000;
  const eurIncrement = config?.eur_increment ?? 20;

  // Compute trade details
  const price = priceData?.price;
  const marketPrice = price?.market_price ?? 0;
  const premiumPercent = price?.premium_percentage ?? 5;

  // Calculate agreed price based on direction
  const agreedPrice = useMemo(() => {
    if (!marketPrice) return 0;
    if (direction === "buy") {
      return marketPrice * (1 + premiumPercent / 100);
    } else {
      return marketPrice * (1 - premiumPercent / 100);
    }
  }, [marketPrice, premiumPercent, direction]);

  // Calculate sats amount
  const satsAmount = useMemo(() => {
    if (!agreedPrice) return 0;
    const eurValue = eurAmount / 100;
    const btcAmount = eurValue / agreedPrice;
    return Math.floor(btcAmount * 100_000_000);
  }, [eurAmount, agreedPrice]);

  // Check if Lightning is disabled due to threshold
  const isLightningDisabled = useMemo(() => {
    return eurAmount > LIGHTNING_MAX_EUR * 100;
  }, [eurAmount]);

  // Auto-switch to onchain if Lightning becomes disabled
  useEffect(() => {
    if (isLightningDisabled && bitcoinTransferMethod === "lightning") {
      setBitcoinTransferMethod("onchain");
    }
  }, [isLightningDisabled, bitcoinTransferMethod]);

  // Fetch slots when date is selected
  useEffect(() => {
    if (selectedDate && user && isAuthorized) {
      fetchSlots(selectedDate);
    }
  }, [selectedDate, user, isAuthorized, fetchSlots]);

  // Fetch user trades when entering booking step
  useEffect(() => {
    if (!user || !isAuthorized || wizardStep !== "booking") return;

    const fetchUserTrades = async () => {
      try {
        const data = await tradesApi.getTrades();
        setUserTrades(data);
      } catch (err) {
        console.error("Failed to fetch user trades:", err);
        // Don't block the UI if this fails
      }
    };

    fetchUserTrades();
  }, [user, isAuthorized, wizardStep]);

  // Check if a date has an existing trade (only consider booked trades, not cancelled ones)
  const getExistingTradeOnDate = useCallback(
    (date: Date): ExchangeResponse | null => {
      const dateStr = formatDate(date);
      return (
        userTrades.find((trade) => {
          const tradeDate = formatDate(new Date(trade.slot_start));
          return tradeDate === dateStr && trade.status === "booked";
        }) || null
      );
    },
    [userTrades]
  );

  const handleDateSelect = (date: Date) => {
    const dateStr = formatDate(date);
    if (!datesWithAvailability.has(dateStr)) {
      return;
    }

    // Check if user already has a trade on this date
    const existingTrade = getExistingTradeOnDate(date);
    if (existingTrade) {
      setExistingTradeOnSelectedDate(existingTrade);
      setSelectedDate(null);
      setSelectedSlot(null);
      setError(null);
    } else {
      setExistingTradeOnSelectedDate(null);
      setSelectedDate(date);
    }
  };

  const handleSlotSelect = (slot: components["schemas"]["BookableSlot"]) => {
    setSelectedSlot(slot);
    setError(null);
    setWizardStep("confirmation");
  };

  const handleContinueToBooking = () => {
    setWizardStep("booking");
    setError(null);
  };

  const handleBackToDetails = () => {
    setWizardStep("details");
    setSelectedDate(null);
    setSelectedSlot(null);
    setError(null);
    setExistingTradeOnSelectedDate(null);
  };

  const handleBackToBooking = () => {
    setWizardStep("booking");
    setError(null);
  };

  const handleBook = async () => {
    if (!selectedSlot) return;

    setIsBooking(true);
    setError(null);
    setExistingTradeId(null);

    try {
      await exchangeApi.createExchange({
        slot_start: selectedSlot.start_time,
        direction,
        bitcoin_transfer_method: bitcoinTransferMethod,
        eur_amount: eurAmount,
      });

      // Redirect to trades page after successful booking
      router.push("/trades");
    } catch (err) {
      const errorMessage = extractApiErrorMessage(err, "Failed to book trade");
      setError(errorMessage);

      // Check if it's a "same day" error and extract trade public_id (UUID)
      const tradeIdMatch = errorMessage.match(/Trade ID: ([a-f0-9-]{36})/i);
      if (tradeIdMatch) {
        setExistingTradeId(tradeIdMatch[1]);
      } else {
        setExistingTradeId(null);
      }

      setIsBooking(false);
    }
  };

  if (isLoading) {
    return <LoadingState />;
  }

  if (!isAuthorized) {
    return null;
  }

  const isPriceStale = priceData?.price?.is_stale ?? false;

  return (
    <main style={layoutStyles.main}>
      <Header currentPage="exchange" />
      <div style={styles.content}>
        <h1 style={typographyStyles.pageTitle}>{t("page.title")}</h1>
        <p style={typographyStyles.pageSubtitle}>{t("page.subtitle")}</p>

        {error && (
          <div style={bannerStyles.errorBanner}>
            {error}
            {existingTradeId && (
              <div style={styles.errorLink}>
                <a href={`/trades/${existingTradeId}`} style={styles.errorLinkAnchor}>
                  {t("page.viewExistingTrade")}
                </a>
              </div>
            )}
          </div>
        )}

        {/* Price Display */}
        <PriceDisplay
          priceData={priceData}
          isLoading={isPriceLoading}
          error={priceError}
          lastUpdate={lastPriceUpdate}
          direction={direction}
          agreedPrice={agreedPrice}
        />

        {/* Step Indicator */}
        <StepIndicator currentStep={wizardStep} />

        {/* Step 1: Exchange Details */}
        {wizardStep === "details" && (
          <ExchangeDetailsStep
            direction={direction}
            onDirectionChange={setDirection}
            bitcoinTransferMethod={bitcoinTransferMethod}
            onBitcoinTransferMethodChange={setBitcoinTransferMethod}
            eurAmount={eurAmount}
            onEurAmountChange={setEurAmount}
            satsAmount={satsAmount}
            eurMin={eurMin}
            eurMax={eurMax}
            eurIncrement={eurIncrement}
            isPriceStale={isPriceStale}
            hasPrice={!!priceData?.price}
            onContinue={handleContinueToBooking}
          />
        )}

        {/* Step 2: Booking */}
        {wizardStep === "booking" && (
          <BookingStep
            direction={direction}
            bitcoinTransferMethod={bitcoinTransferMethod}
            eurAmount={eurAmount}
            satsAmount={satsAmount}
            dates={dates}
            selectedDate={selectedDate}
            availableSlots={availableSlots}
            selectedSlot={selectedSlot}
            datesWithAvailability={datesWithAvailability}
            isLoadingSlots={isLoadingSlots}
            isLoadingAvailability={isLoadingAvailability}
            existingTradeOnSelectedDate={existingTradeOnSelectedDate}
            userTrades={userTrades}
            onDateSelect={handleDateSelect}
            onSlotSelect={handleSlotSelect}
            onBackToDetails={handleBackToDetails}
          />
        )}

        {/* Step 3: Confirmation */}
        {wizardStep === "confirmation" && selectedSlot && (
          <ConfirmationStep
            selectedSlot={selectedSlot}
            selectedDate={selectedDate}
            direction={direction}
            bitcoinTransferMethod={bitcoinTransferMethod}
            eurAmount={eurAmount}
            satsAmount={satsAmount}
            agreedPrice={agreedPrice}
            isBooking={isBooking}
            isPriceStale={isPriceStale}
            onConfirm={handleBook}
            onBack={handleBackToBooking}
          />
        )}
      </div>
    </main>
  );
}
