"use client";

import { useSyncExternalStore } from "react";
import {
  createEmptyAutodiagnosticAnswers,
  normalizeAutodiagnosticAnswers,
  normalizeAutodiagnosticResult,
  type AutodiagnosticAnswers,
} from "@/lib/autodiagnostic-shared";
import {
  buildOnboardingPromptContext,
  createEmptyOnboardingState,
  emptyOnboardingAnswers,
  isOnboardingComplete,
  normalizeManagerialLevel,
  type OnboardingState,
  type OnboardingUpdateInput,
} from "@/lib/onboarding-shared";
import type {
  DemoCoachConversationRecord,
  DemoSessionRecord,
  UserProgressOverview,
} from "@/lib/types";

const STORAGE_KEY = "evolia-demo-session:v1";
const STORE_EVENT = "evolia-demo-session:change";

export type DemoBrowserState = {
  onboarding: OnboardingState;
  sessions: DemoSessionRecord[];
  conversations: DemoCoachConversationRecord[];
  ui: {
    homeTutorialCompleted: boolean;
  };
};

export type MandatoryOnboardingPath =
  | "/onboarding"
  | "/onboarding/autodiagnostique"
  | "/onboarding/autodiagnostique/resultat"
  | "/onboarding/plan-action";

const EMPTY_STATE: DemoBrowserState = {
  onboarding: createEmptyOnboardingState(),
  sessions: [],
  conversations: [],
  ui: {
    homeTutorialCompleted: false,
  },
};

let cachedRawValue: string | null | undefined;
let cachedState: DemoBrowserState = EMPTY_STATE;

function isBrowser() {
  return typeof window !== "undefined";
}

function sortSessions(sessions: DemoSessionRecord[]) {
  return [...sessions].sort(
    (left, right) =>
      new Date(right.updatedAt).getTime() - new Date(left.updatedAt).getTime(),
  );
}

function sortConversations(conversations: DemoCoachConversationRecord[]) {
  return [...conversations].sort((left, right) => {
    const leftKey = left.lastMessageAt ?? left.updatedAt;
    const rightKey = right.lastMessageAt ?? right.updatedAt;

    return new Date(rightKey).getTime() - new Date(leftKey).getTime();
  });
}

function normalizeOnboardingAnswers(value: unknown) {
  const mergedAnswers = {
    ...emptyOnboardingAnswers,
    ...(value && typeof value === "object" ? (value as Partial<typeof emptyOnboardingAnswers>) : {}),
  };

  return {
    industrySector:
      typeof mergedAnswers.industrySector === "string"
        ? mergedAnswers.industrySector
        : "",
    department:
      typeof mergedAnswers.department === "string" ? mergedAnswers.department : "",
    jobTitle:
      typeof mergedAnswers.jobTitle === "string" ? mergedAnswers.jobTitle : "",
    managerialLevel: normalizeManagerialLevel(mergedAnswers.managerialLevel),
    companySize:
      typeof mergedAnswers.companySize === "string"
        ? mergedAnswers.companySize
        : "",
    companyContext:
      typeof mergedAnswers.companyContext === "string"
        ? mergedAnswers.companyContext
        : "",
    workMode:
      typeof mergedAnswers.workMode === "string" ? mergedAnswers.workMode : "",
  };
}

function sanitizeAutodiagnosticAnswerPatch(
  value: Partial<AutodiagnosticAnswers> | undefined,
) {
  const nextPatch: Partial<AutodiagnosticAnswers> = {};

  if (!value) {
    return nextPatch;
  }

  for (const [key, answer] of Object.entries(value)) {
    if (
      answer === "" ||
      answer === "A" ||
      answer === "B" ||
      answer === "C" ||
      answer === "D"
    ) {
      nextPatch[key] = answer;
    }
  }

  return nextPatch;
}

function normalizeOnboardingState(value: unknown): OnboardingState {
  if (!value || typeof value !== "object") {
    return createEmptyOnboardingState();
  }

  const record = value as Partial<OnboardingState>;
  const answers = normalizeOnboardingAnswers(record.answers);
  const autodiagnosticAnswers = normalizeAutodiagnosticAnswers(
    record.autodiagnosticAnswers,
  );
  const autodiagnosticResult = normalizeAutodiagnosticResult(
    record.autodiagnosticResult,
  );
  const promptContext =
    typeof record.promptContext === "string"
      ? record.promptContext
      : buildOnboardingPromptContext(answers);
  const autodiagnosticPromptContext =
    typeof record.autodiagnosticPromptContext === "string"
      ? record.autodiagnosticPromptContext
      : "";
  const onboardingCompleted =
    record.onboardingCompleted === true && isOnboardingComplete(answers);
  const autodiagnosticCompleted =
    record.autodiagnosticCompleted === true &&
    autodiagnosticResult !== null &&
    autodiagnosticResult.managerialLevel === answers.managerialLevel;

  return {
    answers,
    promptContext,
    actionPlanPrompt:
      typeof record.actionPlanPrompt === "string" ? record.actionPlanPrompt : "",
    autodiagnosticAnswers,
    autodiagnosticResult,
    autodiagnosticPromptContext:
      autodiagnosticResult !== null ? autodiagnosticPromptContext : "",
    onboardingCompleted,
    actionPlanCompleted: record.actionPlanCompleted === true,
    autodiagnosticCompleted,
    autodiagnosticResultAcknowledged:
      autodiagnosticCompleted &&
      record.autodiagnosticResultAcknowledged === true,
  };
}

function normalizeUiState(
  value: unknown,
): DemoBrowserState["ui"] {
  if (!value || typeof value !== "object") {
    return {
      homeTutorialCompleted: false,
    };
  }

  return {
    homeTutorialCompleted:
      Reflect.get(value, "homeTutorialCompleted") === true,
  };
}

function parseState(rawValue: string | null): DemoBrowserState {
  if (!rawValue) {
    return EMPTY_STATE;
  }

  try {
    const parsed = JSON.parse(rawValue) as Partial<DemoBrowserState>;

    return {
      onboarding: normalizeOnboardingState(parsed.onboarding),
      sessions: Array.isArray(parsed.sessions)
        ? sortSessions(parsed.sessions as DemoSessionRecord[])
        : [],
      conversations: Array.isArray(parsed.conversations)
        ? sortConversations(parsed.conversations as DemoCoachConversationRecord[])
        : [],
      ui: normalizeUiState(parsed.ui),
    };
  } catch {
    if (isBrowser()) {
      window.sessionStorage.removeItem(STORAGE_KEY);
    }

    return EMPTY_STATE;
  }
}

function readCachedState() {
  if (!isBrowser()) {
    return EMPTY_STATE;
  }

  const rawValue = window.sessionStorage.getItem(STORAGE_KEY);

  if (cachedRawValue === rawValue) {
    return cachedState;
  }

  cachedRawValue = rawValue;
  cachedState = parseState(rawValue);
  return cachedState;
}

function dispatchStoreChange() {
  if (!isBrowser()) {
    return;
  }

  window.dispatchEvent(new Event(STORE_EVENT));
}

export function getDemoBrowserState(): DemoBrowserState {
  return readCachedState();
}

function saveDemoBrowserState(nextState: DemoBrowserState) {
  if (!isBrowser()) {
    return;
  }

  const serialized = JSON.stringify(nextState);
  window.sessionStorage.setItem(STORAGE_KEY, serialized);
  cachedRawValue = serialized;
  cachedState = parseState(serialized);
  dispatchStoreChange();
}

export function updateDemoBrowserState(
  updater: (current: DemoBrowserState) => DemoBrowserState,
) {
  const current = getDemoBrowserState();
  const nextState = updater(current);
  saveDemoBrowserState(nextState);
  return nextState;
}

function subscribe(listener: () => void) {
  if (!isBrowser()) {
    return () => undefined;
  }

  const handler = () => listener();

  window.addEventListener(STORE_EVENT, handler);
  window.addEventListener("storage", handler);

  return () => {
    window.removeEventListener(STORE_EVENT, handler);
    window.removeEventListener("storage", handler);
  };
}

export function useDemoBrowserState() {
  return useSyncExternalStore(
    subscribe,
    getDemoBrowserState,
    () => EMPTY_STATE,
  );
}

export function clearDemoBrowserState() {
  if (!isBrowser()) {
    return;
  }

  window.sessionStorage.removeItem(STORAGE_KEY);
  cachedRawValue = null;
  cachedState = EMPTY_STATE;
  dispatchStoreChange();
}

function applyOnboardingUpdate(
  currentState: OnboardingState,
  input: OnboardingUpdateInput,
): OnboardingState {
  const nextAnswers = {
    ...currentState.answers,
    ...Object.fromEntries(
      Object.entries(input.answers ?? {}).map(([key, value]) => [
        key,
        typeof value === "string" ? value.trim() : value,
      ]),
    ),
  };
  nextAnswers.managerialLevel = normalizeManagerialLevel(nextAnswers.managerialLevel);

  const managerialLevelChanged =
    currentState.answers.managerialLevel.length > 0 &&
    nextAnswers.managerialLevel !== currentState.answers.managerialLevel;

  const nextAutodiagnosticAnswers: AutodiagnosticAnswers = {
    ...currentState.autodiagnosticAnswers,
  };

  for (const [key, value] of Object.entries(
    sanitizeAutodiagnosticAnswerPatch(input.autodiagnosticAnswers),
  )) {
    if (value !== undefined) {
      nextAutodiagnosticAnswers[key] = value;
    }
  }

  const autodiagnosticAnswersChanged =
    JSON.stringify(nextAutodiagnosticAnswers) !==
    JSON.stringify(currentState.autodiagnosticAnswers);

  const autodiagnosticResultInput =
    input.autodiagnosticResult === undefined
      ? currentState.autodiagnosticResult
      : input.autodiagnosticResult;

  const nextAutodiagnosticResult = managerialLevelChanged
    ? null
    : autodiagnosticResultInput;

  const autodiagnosticPromptContext =
    managerialLevelChanged || nextAutodiagnosticResult === null
      ? ""
      : typeof input.autodiagnosticPromptContext === "string"
        ? input.autodiagnosticPromptContext.trim()
        : currentState.autodiagnosticPromptContext;

  const onboardingCompleted =
    typeof input.completeOnboarding === "boolean"
      ? input.completeOnboarding && isOnboardingComplete(nextAnswers)
      : currentState.onboardingCompleted && isOnboardingComplete(nextAnswers);

  const autodiagnosticInvalidated =
    managerialLevelChanged ||
    (autodiagnosticAnswersChanged && input.completeAutodiagnostic !== true);

  const autodiagnosticCompleted =
    autodiagnosticInvalidated || nextAutodiagnosticResult === null
      ? false
      : typeof input.completeAutodiagnostic === "boolean"
        ? input.completeAutodiagnostic
        : currentState.autodiagnosticCompleted;

  const autodiagnosticResultAcknowledged =
    autodiagnosticInvalidated || nextAutodiagnosticResult === null
      ? false
      : typeof input.acknowledgeAutodiagnosticResult === "boolean"
        ? input.acknowledgeAutodiagnosticResult
        : currentState.autodiagnosticResultAcknowledged;

  const shouldResetActionPlan =
    managerialLevelChanged ||
    autodiagnosticAnswersChanged ||
    input.autodiagnosticResult !== undefined ||
    input.completeAutodiagnostic === true;

  const actionPlanPrompt = shouldResetActionPlan
    ? ""
    : typeof input.actionPlanPrompt === "string"
      ? input.actionPlanPrompt.trim()
      : currentState.actionPlanPrompt;

  const actionPlanCompleted = shouldResetActionPlan
    ? false
    : typeof input.completeActionPlan === "boolean"
      ? input.completeActionPlan
      : currentState.actionPlanCompleted;

  return {
    answers: nextAnswers,
    promptContext: buildOnboardingPromptContext(nextAnswers),
    actionPlanPrompt,
    autodiagnosticAnswers: managerialLevelChanged
      ? createEmptyAutodiagnosticAnswers()
      : nextAutodiagnosticAnswers,
    autodiagnosticResult: nextAutodiagnosticResult,
    autodiagnosticPromptContext: autodiagnosticPromptContext,
    onboardingCompleted,
    actionPlanCompleted,
    autodiagnosticCompleted,
    autodiagnosticResultAcknowledged,
  };
}

export function getDemoOnboardingState() {
  return getDemoBrowserState().onboarding;
}

export function getMandatoryOnboardingPath(
  onboarding: OnboardingState,
): MandatoryOnboardingPath | null {
  if (!onboarding.onboardingCompleted) {
    return "/onboarding";
  }

  if (!onboarding.autodiagnosticCompleted) {
    return "/onboarding/autodiagnostique";
  }

  if (!onboarding.autodiagnosticResultAcknowledged) {
    return "/onboarding/autodiagnostique/resultat";
  }

  if (!onboarding.actionPlanCompleted) {
    return "/onboarding/plan-action";
  }

  return null;
}

export function updateDemoOnboardingState(input: OnboardingUpdateInput) {
  return updateDemoBrowserState((current) => ({
    ...current,
    onboarding: applyOnboardingUpdate(current.onboarding, input),
  })).onboarding;
}

export function getDemoSession(sessionId: string) {
  return getDemoBrowserState().sessions.find(
    (session) => session.sessionId === sessionId,
  );
}

export function upsertDemoSession(nextSession: DemoSessionRecord) {
  return updateDemoBrowserState((current) => ({
    ...current,
    sessions: sortSessions([
      nextSession,
      ...current.sessions.filter(
        (session) => session.sessionId !== nextSession.sessionId,
      ),
    ]),
  }));
}

export function getDemoProgressOverview(
  state: DemoBrowserState = getDemoBrowserState(),
): UserProgressOverview {
  const completedSessions = state.sessions.filter(
    (session) => session.finalAssessment !== null,
  );

  return {
    companyMemberId: "demo-member",
    totalSessions: state.sessions.length,
    completedSessions: completedSessions.length,
    resolvedSessions: completedSessions.filter(
      (session) => session.status === "resolved",
    ).length,
    escalatedSessions: completedSessions.filter(
      (session) => session.status === "escalated",
    ).length,
    latestActivityAt: state.sessions[0]?.updatedAt ?? null,
  };
}

export function getDemoConversation(conversationId: string) {
  return getDemoBrowserState().conversations.find(
    (conversation) => conversation.id === conversationId,
  );
}

export function upsertDemoConversation(
  nextConversation: DemoCoachConversationRecord,
) {
  return updateDemoBrowserState((current) => ({
    ...current,
    conversations: sortConversations([
      nextConversation,
      ...current.conversations.filter(
        (conversation) => conversation.id !== nextConversation.id,
      ),
      ]),
  }));
}

export function completeDemoHomeTutorial() {
  return updateDemoBrowserState((current) => ({
    ...current,
    ui: {
      ...current.ui,
      homeTutorialCompleted: true,
    },
  })).ui;
}
