/**
 * Eligibility Check Store
 *
 * Manages state for the public eligibility check flow.
 * Two paths:
 * 1. "Create Account & Submit" (primary) → OTP → Complete Account → Success
 * 2. "Just Submit Request" (secondary) → SF Account + Case → Success
 */

import { create } from "zustand";
import { logger } from "@/core/logger";
import { getErrorMessage } from "@/shared/utils";
import type { JapanAddressFormData } from "@/features/address/components/JapanAddressForm";
import {
  guestEligibilityCheck,
  sendVerificationCode,
  verifyCode,
  signupWithEligibility,
} from "@/features/get-started/api/get-started.api";
import { prepareWhmcsAddressFields } from "@customer-portal/domain/address";

// ============================================================================
// Types
// ============================================================================

// Step constants to avoid duplicate string literals
const STEP_FORM = "form" as const;
const STEP_OTP = "otp" as const;
const STEP_COMPLETE_ACCOUNT = "complete-account" as const;
const STEP_SUCCESS = "success" as const;

export type EligibilityCheckStep =
  | typeof STEP_FORM
  | typeof STEP_OTP
  | typeof STEP_COMPLETE_ACCOUNT
  | typeof STEP_SUCCESS;

export interface EligibilityCheckFormData {
  firstName: string;
  lastName: string;
  email: string;
  address: JapanAddressFormData | null;
}

export interface EligibilityCheckAccountData {
  password: string;
  confirmPassword: string;
  phone: string;
  dateOfBirth: string;
  gender: "male" | "female" | "other" | "";
  acceptTerms: boolean;
  marketingConsent: boolean;
}

export interface EligibilityCheckState {
  // Step management
  step: EligibilityCheckStep;

  // Form data
  formData: EligibilityCheckFormData;
  accountData: EligibilityCheckAccountData;
  isAddressComplete: boolean;

  // Session & success state
  sessionToken: string | null;
  requestId: string | null;
  hasAccount: boolean;

  // OTP state
  attemptsRemaining: number | null;
  resendDisabled: boolean;
  resendCountdown: number;

  // Loading & error
  loading: boolean;
  error: string | null;
  otpError: string | null;

  // Submit type tracking (for loading indicator per button)
  submitType: "create" | "check" | null;

  // Timer reference (internal)
  _resendTimerId: ReturnType<typeof setInterval> | null;

  // Actions
  submitOnly: () => Promise<boolean>;
  submitAndCreate: () => Promise<boolean>;
  verifyOtp: (code: string) => Promise<boolean>;
  resendOtp: () => Promise<boolean>;
  completeAccount: () => Promise<boolean>;

  // Navigation
  goToStep: (step: EligibilityCheckStep) => void;
  goBack: () => void;

  // Form updates
  updateFormData: (data: Partial<EligibilityCheckFormData>) => void;
  updateAccountData: (data: Partial<EligibilityCheckAccountData>) => void;
  setAddressComplete: (isComplete: boolean) => void;

  // Error management
  clearError: () => void;
  clearOtpError: () => void;

  // Timer management
  startResendTimer: () => void;
  stopResendTimer: () => void;

  // Lifecycle
  cleanup: () => void;
  reset: () => void;
}

// ============================================================================
// Initial State
// ============================================================================

const initialFormData: EligibilityCheckFormData = {
  firstName: "",
  lastName: "",
  email: "",
  address: null,
};

const initialAccountData: EligibilityCheckAccountData = {
  password: "",
  confirmPassword: "",
  phone: "",
  dateOfBirth: "",
  gender: "",
  acceptTerms: false,
  marketingConsent: false,
};

const initialState = {
  step: STEP_FORM as EligibilityCheckStep,
  formData: initialFormData,
  accountData: initialAccountData,
  isAddressComplete: false,
  sessionToken: null,
  requestId: null,
  hasAccount: false,
  attemptsRemaining: null,
  resendDisabled: false,
  resendCountdown: 0,
  loading: false,
  error: null,
  otpError: null,
  submitType: null as "create" | "check" | null,
  _resendTimerId: null,
};

// ============================================================================
// Address Building Helper
// ============================================================================

interface EligibilityCheckAddress {
  address1: string;
  address2?: string;
  city: string;
  state: string;
  postcode: string;
  country: "JP";
  prefectureJa?: string;
  cityJa?: string;
  townJa?: string;
  streetAddress?: string;
  buildingName?: string;
  roomNumber?: string;
}

function buildEligibilityAddress(addressData: JapanAddressFormData): EligibilityCheckAddress {
  const whmcsAddress = prepareWhmcsAddressFields(addressData);

  const address: EligibilityCheckAddress = {
    address1: whmcsAddress.address1 || "",
    city: whmcsAddress.city || "",
    state: whmcsAddress.state || "",
    postcode: whmcsAddress.postcode || "",
    country: "JP",
  };

  if (whmcsAddress.address2) address.address2 = whmcsAddress.address2;
  if (addressData.prefectureJa) address.prefectureJa = addressData.prefectureJa;
  if (addressData.cityJa) address.cityJa = addressData.cityJa;
  if (addressData.townJa) address.townJa = addressData.townJa;
  if (addressData.streetAddress) address.streetAddress = addressData.streetAddress;
  if (addressData.buildingName) address.buildingName = addressData.buildingName;
  if (addressData.roomNumber) address.roomNumber = addressData.roomNumber;

  return address;
}

// ============================================================================
// Action Implementations (extracted to reduce store function length)
// ============================================================================

type StoreGet = () => EligibilityCheckState;
type StoreSet = (partial: Partial<EligibilityCheckState>) => void;

async function submitOnlyAction(get: StoreGet, set: StoreSet): Promise<boolean> {
  const { formData, isAddressComplete } = get();

  if (!isAddressComplete || !formData.address) {
    set({ error: "Please complete the address form" });
    return false;
  }

  set({ loading: true, error: null, submitType: "check" });

  try {
    const result = await guestEligibilityCheck({
      email: formData.email.trim(),
      firstName: formData.firstName.trim(),
      lastName: formData.lastName.trim(),
      address: buildEligibilityAddress(formData.address),
      continueToAccount: false,
    });

    if (result.submitted) {
      set({
        loading: false,
        submitType: null,
        requestId: result.requestId || null,
        hasAccount: false,
        step: STEP_SUCCESS,
      });
      return true;
    }

    set({
      loading: false,
      submitType: null,
      error: result.message || "Failed to submit eligibility check",
    });
    return false;
  } catch (err) {
    const message = getErrorMessage(err);
    logger.error("Failed to submit eligibility check", { error: message, email: formData.email });
    set({ loading: false, submitType: null, error: message });
    return false;
  }
}

async function submitAndCreateAction(get: StoreGet, set: StoreSet): Promise<boolean> {
  const { formData, isAddressComplete } = get();

  if (!isAddressComplete || !formData.address) {
    set({ error: "Please complete the address form" });
    return false;
  }

  set({ loading: true, error: null, submitType: "create" });

  try {
    const result = await sendVerificationCode({ email: formData.email.trim() });

    if (result.sent) {
      set({ loading: false, submitType: null, step: STEP_OTP });
      get().startResendTimer();
      return true;
    }

    set({
      loading: false,
      submitType: null,
      error: result.message || "Failed to send verification code",
    });
    return false;
  } catch (err) {
    const message = getErrorMessage(err);
    logger.error("Failed to send OTP", { error: message, email: formData.email });
    set({ loading: false, submitType: null, error: message });
    return false;
  }
}

async function verifyOtpAction(get: StoreGet, set: StoreSet, code: string): Promise<boolean> {
  if (code.length !== 6) return false;

  const { formData } = get();
  set({ loading: true, otpError: null });

  try {
    const result = await verifyCode({ email: formData.email.trim(), code });

    if (!result.verified || !result.sessionToken) {
      set({
        loading: false,
        otpError: result.error || "Verification failed. Please try again.",
        attemptsRemaining: result.attemptsRemaining ?? null,
      });
      return false;
    }

    get().stopResendTimer();

    if (result.accountStatus === "portal_exists") {
      set({
        loading: false,
        otpError: "An account already exists with this email. Please log in instead.",
      });
      return false;
    }

    if (result.accountStatus === "whmcs_unmapped") {
      set({
        loading: false,
        otpError: "A billing account exists with this email. Please use account linking instead.",
      });
      return false;
    }

    set({ loading: false, sessionToken: result.sessionToken, step: STEP_COMPLETE_ACCOUNT });
    return true;
  } catch (err) {
    const message = getErrorMessage(err);
    logger.error("Failed to verify OTP", { error: message, email: formData.email });
    set({ loading: false, otpError: message });
    return false;
  }
}

async function resendOtpAction(get: StoreGet, set: StoreSet): Promise<boolean> {
  const { formData, resendDisabled, loading } = get();

  if (resendDisabled || loading) return false;

  set({ loading: true, otpError: null });

  try {
    const result = await sendVerificationCode({ email: formData.email.trim() });

    if (result.sent) {
      set({ loading: false });
      get().startResendTimer();
      return true;
    }

    set({ loading: false, otpError: result.message || "Failed to resend code" });
    return false;
  } catch (err) {
    const message = getErrorMessage(err);
    logger.error("Failed to resend OTP", { error: message, email: formData.email });
    set({ loading: false, otpError: message });
    return false;
  }
}

async function completeAccountAction(get: StoreGet, set: StoreSet): Promise<boolean> {
  const { sessionToken, formData, accountData } = get();

  if (!sessionToken) {
    set({ error: "Session expired. Please start over." });
    return false;
  }

  if (!formData.address) {
    set({ error: "Address information is missing." });
    return false;
  }

  set({ loading: true, error: null });

  try {
    const whmcsAddress = prepareWhmcsAddressFields(formData.address);

    const result = await signupWithEligibility({
      sessionToken,
      firstName: formData.firstName.trim(),
      lastName: formData.lastName.trim(),
      address: {
        address1: whmcsAddress.address1 || "",
        ...(whmcsAddress.address2 && { address2: whmcsAddress.address2 }),
        city: whmcsAddress.city || "",
        state: whmcsAddress.state || "",
        postcode: whmcsAddress.postcode || "",
        country: "JP",
      },
      phone: accountData.phone.trim(),
      password: accountData.password,
      dateOfBirth: accountData.dateOfBirth,
      gender: accountData.gender as "male" | "female" | "other",
      acceptTerms: accountData.acceptTerms,
      marketingConsent: accountData.marketingConsent,
    });

    if (result.success) {
      set({
        loading: false,
        requestId: result.eligibilityRequestId || null,
        hasAccount: true,
        step: STEP_SUCCESS,
      });
      return true;
    }

    set({ loading: false, error: result.message || "Failed to create account" });
    return false;
  } catch (err) {
    const message = getErrorMessage(err);
    logger.error("Failed to complete account", { error: message, email: formData.email });
    set({ loading: false, error: message });
    return false;
  }
}

// ============================================================================
// Store
// ============================================================================

export const useEligibilityCheckStore = create<EligibilityCheckState>()((set, get) => ({
  ...initialState,

  submitOnly: () => submitOnlyAction(get, set),
  submitAndCreate: () => submitAndCreateAction(get, set),
  verifyOtp: (code: string) => verifyOtpAction(get, set, code),
  resendOtp: () => resendOtpAction(get, set),
  completeAccount: () => completeAccountAction(get, set),

  goToStep: (step: EligibilityCheckStep) => {
    const currentStep = get().step;
    set({ step, error: null, otpError: null });

    if (step === STEP_FORM) {
      get().stopResendTimer();
      set({ sessionToken: null, attemptsRemaining: null });
    } else if (step === STEP_OTP && currentStep === STEP_COMPLETE_ACCOUNT) {
      set({ sessionToken: null, attemptsRemaining: null });
    }
  },

  goBack: () => {
    const { step } = get();
    const stepOrder: EligibilityCheckStep[] = [STEP_FORM, STEP_OTP, STEP_COMPLETE_ACCOUNT];
    const currentIndex = stepOrder.indexOf(step);

    if (currentIndex > 0) {
      const prevStep = stepOrder[currentIndex - 1];
      if (prevStep) get().goToStep(prevStep);
    }
  },

  updateFormData: (data: Partial<EligibilityCheckFormData>) => {
    set({ formData: { ...get().formData, ...data } });
  },

  updateAccountData: (data: Partial<EligibilityCheckAccountData>) => {
    set({ accountData: { ...get().accountData, ...data } });
  },

  setAddressComplete: (isComplete: boolean) => {
    set({ isAddressComplete: isComplete });
  },

  clearError: () => set({ error: null }),
  clearOtpError: () => set({ otpError: null }),

  startResendTimer: () => {
    const { _resendTimerId } = get();
    if (_resendTimerId) clearInterval(_resendTimerId);

    set({ resendDisabled: true, resendCountdown: 60 });

    const timerId = setInterval(() => {
      const { resendCountdown } = get();

      if (resendCountdown <= 1) {
        clearInterval(timerId);
        set({ resendDisabled: false, resendCountdown: 0, _resendTimerId: null });
      } else {
        set({ resendCountdown: resendCountdown - 1 });
      }
    }, 1000);

    set({ _resendTimerId: timerId });
  },

  stopResendTimer: () => {
    const { _resendTimerId } = get();
    if (_resendTimerId) {
      clearInterval(_resendTimerId);
      set({ _resendTimerId: null, resendDisabled: false, resendCountdown: 0 });
    }
  },

  cleanup: () => {
    const { _resendTimerId } = get();
    if (_resendTimerId) {
      clearInterval(_resendTimerId);
      set({ _resendTimerId: null });
    }
  },

  reset: () => {
    const { _resendTimerId } = get();
    if (_resendTimerId) clearInterval(_resendTimerId);
    set({ ...initialState, _resendTimerId: null });
  },
}));
