import { cookies } from "next/headers";
import type { SupabaseClient } from "@supabase/supabase-js";
import type { RouteAppContext } from "@/lib/app-auth";
import { getRouteAppContext, isAuthDisabled } from "@/lib/app-auth";
import { createEmptyAutodiagnosticAnswers } from "@/lib/autodiagnostic-shared";
import {
  buildOnboardingPromptContext,
  createOnboardingVisitorId,
  createEmptyOnboardingState,
  emptyOnboardingAnswers,
  isOnboardingComplete,
  ONBOARDING_VISITOR_COOKIE,
  type OnboardingAnswers,
  type OnboardingState,
  type OnboardingUpdateInput,
} from "@/lib/onboarding-shared";
import { OnboardingAnswersSchema, OnboardingUpdateSchema } from "@/lib/schemas";
import { createAdminClient } from "@/lib/supabase/admin";

type OnboardingRow = {
  viewer_key: string;
  visitor_id: string | null;
  auth_user_id: string | null;
  company_member_id: string | null;
  client_id: string | null;
  profile_payload: unknown;
  prompt_context: string | null;
  onboarding_completed_at: string | null;
  action_plan_completed_at: string | null;
  autodiagnostic_completed_at: string | null;
};

export type ResolvedOnboardingViewer = {
  viewerKey: string;
  visitorId: string | null;
  cookieToSet: string | null;
  authUserId: string | null;
  companyMemberId: string | null;
  clientId: string | null;
};

type ResolveOnboardingViewerOptions = {
  routeContext?: Pick<RouteAppContext, "user" | "member">;
};

type GetCurrentOnboardingStateOptions = {
  routeContext?: Pick<RouteAppContext, "user" | "member">;
};

function getVisitorViewerKey(visitorId: string) {
  return `visitor:${visitorId}`;
}

function toNullableTrimmedString(value: unknown) {
  if (typeof value !== "string") {
    return null;
  }

  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : null;
}

function isUuid(value: string) {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
    value,
  );
}

function normalizePartialAnswers(value: unknown) {
  const parsed = OnboardingAnswersSchema.partial().safeParse(value);

  if (!parsed.success) {
    return {};
  }

  const output = Object.fromEntries(
    Object.entries(parsed.data).map(([key, answer]) => [key, answer.trim()]),
  );

  return output as Partial<OnboardingAnswers>;
}

function normalizeStoredAnswers(value: unknown): OnboardingAnswers {
  return {
    ...emptyOnboardingAnswers,
    ...normalizePartialAnswers(value),
  };
}

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

  const prompt = Reflect.get(value, "actionPlanPrompt");
  return typeof prompt === "string" ? prompt.trim() : "";
}

async function getOnboardingRowByViewerKey(
  supabase: SupabaseClient,
  viewerKey: string,
) {
  const { data, error } = await supabase
    .from("onboarding_profiles")
    .select(
      "viewer_key, visitor_id, auth_user_id, company_member_id, client_id, profile_payload, prompt_context, onboarding_completed_at, action_plan_completed_at, autodiagnostic_completed_at",
    )
    .eq("viewer_key", viewerKey)
    .maybeSingle();

  if (error) {
    throw error;
  }

  return (data as OnboardingRow | null) ?? null;
}

async function loadOnboardingRow(
  supabase: SupabaseClient,
  viewer: ResolvedOnboardingViewer,
) {
  const directRow = await getOnboardingRowByViewerKey(supabase, viewer.viewerKey);

  if (directRow || !viewer.companyMemberId || !viewer.visitorId) {
    return directRow;
  }

  return getOnboardingRowByViewerKey(
    supabase,
    getVisitorViewerKey(viewer.visitorId),
  );
}

function mapOnboardingRow(row: OnboardingRow | null): OnboardingState {
  if (!row) {
    return createEmptyOnboardingState();
  }

  const emptyState = createEmptyOnboardingState();

  return {
    ...emptyState,
    answers: normalizeStoredAnswers(row.profile_payload),
    promptContext: row.prompt_context ?? "",
    actionPlanPrompt: extractActionPlanPrompt(row.profile_payload),
    autodiagnosticAnswers: createEmptyAutodiagnosticAnswers(),
    autodiagnosticResult: null,
    autodiagnosticPromptContext: "",
    onboardingCompleted: row.onboarding_completed_at !== null,
    actionPlanCompleted: row.action_plan_completed_at !== null,
    autodiagnosticCompleted: row.autodiagnostic_completed_at !== null,
    autodiagnosticResultAcknowledged: false,
  };
}

export async function resolveOnboardingViewer(
  options: ResolveOnboardingViewerOptions = {},
): Promise<ResolvedOnboardingViewer> {
  const cookieStore = await cookies();
  const rawVisitorId = toNullableTrimmedString(
    cookieStore.get(ONBOARDING_VISITOR_COOKIE)?.value,
  );
  const existingVisitorId =
    rawVisitorId && isUuid(rawVisitorId) ? rawVisitorId : null;
  const visitorId = existingVisitorId ?? createOnboardingVisitorId();
  const cookieToSet = existingVisitorId ? null : visitorId;

  if (!isAuthDisabled()) {
    const routeContext = options.routeContext ?? (await getRouteAppContext());
    const { user, member } = routeContext;

    if (user && member && member.status === "active") {
      return {
        viewerKey: `member:${member.id}`,
        visitorId,
        cookieToSet,
        authUserId: user.id,
        companyMemberId: member.id,
        clientId: member.clientId,
      };
    }
  }

  return {
    viewerKey: getVisitorViewerKey(visitorId),
    visitorId,
    cookieToSet,
    authUserId: null,
    companyMemberId: null,
    clientId: null,
  };
}

export async function getCurrentOnboardingState(
  options: GetCurrentOnboardingStateOptions = {},
) {
  const viewer = await resolveOnboardingViewer(options);
  const supabase = createAdminClient() as unknown as SupabaseClient;
  const row = await loadOnboardingRow(supabase, viewer);

  return {
    viewer,
    state: mapOnboardingRow(row),
  };
}

export async function updateOnboardingState(
  viewer: ResolvedOnboardingViewer,
  input: OnboardingUpdateInput,
) {
  const payload = OnboardingUpdateSchema.parse(input);
  const supabase = createAdminClient() as unknown as SupabaseClient;
  const currentRow = await loadOnboardingRow(supabase, viewer);
  const currentState = mapOnboardingRow(currentRow);

  const nextAnswers = {
    ...currentState.answers,
    ...normalizePartialAnswers(payload.answers),
  };
  const nextActionPlanPrompt =
    typeof payload.actionPlanPrompt === "string"
      ? payload.actionPlanPrompt.trim()
      : currentState.actionPlanPrompt;

  if (payload.completeOnboarding && !isOnboardingComplete(nextAnswers)) {
    throw new Error("Tous les champs d'onboarding sont requis.");
  }

  const now = new Date().toISOString();
  const nextOnboardingCompleted =
    payload.completeOnboarding === true
      ? true
      : currentState.onboardingCompleted && isOnboardingComplete(nextAnswers);
  const nextActionPlanCompleted =
    currentState.actionPlanCompleted || payload.completeActionPlan === true;
  const nextAutodiagnosticCompleted =
    currentState.autodiagnosticCompleted ||
    payload.completeAutodiagnostic === true;

  const { data, error } = await supabase
    .from("onboarding_profiles")
    .upsert(
      {
        viewer_key: viewer.viewerKey,
        visitor_id: viewer.visitorId,
        auth_user_id: viewer.authUserId,
        company_member_id: viewer.companyMemberId,
        client_id: viewer.clientId,
        profile_payload: {
          ...nextAnswers,
          actionPlanPrompt: nextActionPlanPrompt,
        },
        prompt_context: buildOnboardingPromptContext(nextAnswers),
        onboarding_completed_at: nextOnboardingCompleted
          ? currentRow?.onboarding_completed_at ?? now
          : null,
        action_plan_completed_at: nextActionPlanCompleted
          ? currentRow?.action_plan_completed_at ?? now
          : null,
        autodiagnostic_completed_at: nextAutodiagnosticCompleted
          ? currentRow?.autodiagnostic_completed_at ?? now
          : null,
      },
      { onConflict: "viewer_key" },
    )
    .select(
      "viewer_key, visitor_id, auth_user_id, company_member_id, client_id, profile_payload, prompt_context, onboarding_completed_at, action_plan_completed_at, autodiagnostic_completed_at",
    )
    .single();

  if (error) {
    throw error;
  }

  return mapOnboardingRow(data as OnboardingRow);
}
