import React from 'react';
import { fetchOnboardingStatus, trackOnboarding } from '../api';
import { useAuth } from '../auth/context';

export type OnboardingProgress = {
  welcomeSeen: boolean;
  packageSelected: boolean;
  eventCreated: boolean;
  lastStep?: string | null;
  adminAppOpenedAt?: string | null;
  selectedPackage?: {
    id: number;
    name: string;
    priceText?: string | null;
    isSubscription?: boolean;
  } | null;
  inviteCreated: boolean;
  brandingConfigured: boolean;
};

type OnboardingUpdate = Partial<OnboardingProgress> & {
  serverStep?: string;
  meta?: Record<string, unknown>;
};

type OnboardingContextValue = {
  progress: OnboardingProgress;
  setProgress: (updater: (prev: OnboardingProgress) => OnboardingProgress) => void;
  markStep: (step: OnboardingUpdate) => void;
  reset: () => void;
};

const DEFAULT_PROGRESS: OnboardingProgress = {
  welcomeSeen: false,
  packageSelected: false,
  eventCreated: false,
  lastStep: null,
  adminAppOpenedAt: null,
  selectedPackage: null,
  inviteCreated: false,
  brandingConfigured: false,
};

const STORAGE_KEY = 'tenant-admin:onboarding-progress';

const OnboardingProgressContext = React.createContext<OnboardingContextValue | undefined>(undefined);

function readStoredProgress(): OnboardingProgress {
  if (typeof window === 'undefined') {
    return DEFAULT_PROGRESS;
  }
  try {
    const raw = window.localStorage.getItem(STORAGE_KEY);
    if (!raw) {
      return DEFAULT_PROGRESS;
    }
    const parsed = JSON.parse(raw) as Partial<OnboardingProgress>;
    return {
      ...DEFAULT_PROGRESS,
      ...parsed,
    };
  } catch (error) {
    console.warn('[OnboardingProgress] Failed to parse stored value', error);
    return DEFAULT_PROGRESS;
  }
}

function writeStoredProgress(progress: OnboardingProgress) {
  if (typeof window === 'undefined') {
    return;
  }
  try {
    window.localStorage.setItem(STORAGE_KEY, JSON.stringify(progress));
  } catch (error) {
    console.warn('[OnboardingProgress] Failed to persist value', error);
  }
}

export function OnboardingProgressProvider({ children }: { children: React.ReactNode }) {
  const [progress, setProgressState] = React.useState<OnboardingProgress>(() => readStoredProgress());
  const [synced, setSynced] = React.useState(false);
  const { status } = useAuth();

  React.useEffect(() => {
    if (status !== 'authenticated') {
      if (synced) {
        setSynced(false);
      }
      return;
    }

    if (synced) {
      return;
    }

    let cancelled = false;

    fetchOnboardingStatus().then((status) => {
      if (cancelled) {
        return;
      }

      if (!status) {
        setSynced(true);
        return;
      }

      setProgressState((prev) => {
        const next: OnboardingProgress = {
          ...prev,
          adminAppOpenedAt: status.steps.admin_app_opened_at ?? prev.adminAppOpenedAt ?? null,
          eventCreated: Boolean(status.steps.event_created ?? prev.eventCreated),
          packageSelected: Boolean(status.steps.selected_packages ?? prev.packageSelected),
          inviteCreated: Boolean(status.steps.invite_created ?? prev.inviteCreated),
          brandingConfigured: Boolean(status.steps.branding_completed ?? prev.brandingConfigured),
        };

        writeStoredProgress(next);

        return next;
      });

      if (!status.steps.admin_app_opened_at) {
        const timestamp = new Date().toISOString();
        trackOnboarding('admin_app_opened').catch(() => {});
        setProgressState((prev) => {
          const next = { ...prev, adminAppOpenedAt: timestamp };
          writeStoredProgress(next);
          return next;
        });
      }

      setSynced(true);
    }).catch(() => {
      if (!cancelled) {
        setSynced(true);
      }
    });

    return () => {
      cancelled = true;
    };
  }, [status, synced]);

  const setProgress = React.useCallback((updater: (prev: OnboardingProgress) => OnboardingProgress) => {
    setProgressState((prev) => {
      const next = updater(prev);
      writeStoredProgress(next);
      return next;
    });
  }, []);

  const markStep = React.useCallback((step: OnboardingUpdate) => {
    const { serverStep, meta, ...rest } = step;

    setProgress((prev) => {
      const derived: Partial<OnboardingProgress> = {};

      switch (serverStep) {
        case 'package_selected':
          derived.packageSelected = true;
          break;
        case 'event_created':
          derived.eventCreated = true;
          break;
        case 'invite_created':
          derived.inviteCreated = true;
          break;
        case 'branding_configured':
          derived.brandingConfigured = true;
          break;
        default:
          break;
      }

      const next: OnboardingProgress = {
        ...prev,
        ...rest,
        ...derived,
        lastStep: typeof rest.lastStep === 'undefined' ? prev.lastStep : rest.lastStep,
      };

      if (serverStep === 'admin_app_opened' && !next.adminAppOpenedAt) {
        next.adminAppOpenedAt = new Date().toISOString();
      }

      return next;
    });

    if (serverStep) {
      trackOnboarding(serverStep, meta).catch(() => {});
    }
  }, [setProgress]);

  const reset = React.useCallback(() => {
    setProgress(() => DEFAULT_PROGRESS);
  }, [setProgress]);

  const value = React.useMemo<OnboardingContextValue>(() => ({
    progress,
    setProgress,
    markStep,
    reset,
  }), [progress, setProgress, markStep, reset]);

  return (
    <OnboardingProgressContext.Provider value={value}>
      {children}
    </OnboardingProgressContext.Provider>
  );
}

export function useOnboardingProgress() {
  const context = React.useContext(OnboardingProgressContext);
  if (!context) {
    throw new Error('useOnboardingProgress must be used within OnboardingProgressProvider');
  }
  return context;
}
