import { getFormProps, getInputProps, useForm } from "@conform-to/react";
import { parseWithZod } from "@conform-to/zod";
import { ArrowLeftIcon, ArrowUpRightIcon } from "@heroicons/react/20/solid";
import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
import { Form, useNavigation } from "@remix-run/react";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { z } from "zod";
import { LoginPageLayout } from "~/components/LoginPageLayout";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { Fieldset } from "~/components/primitives/Fieldset";
import { FormError } from "~/components/primitives/FormError";
import { Header1 } from "~/components/primitives/Headers";
import { Input } from "~/components/primitives/Input";
import { InputGroup } from "~/components/primitives/InputGroup";
import { Paragraph } from "~/components/primitives/Paragraph";
import { Spinner } from "~/components/primitives/Spinner";
import { authenticator } from "~/services/auth.server";

type Reason = "default" | "domain_policy" | "oauth_blocked" | "expired";

const REASON_VALUES: ReadonlySet<Reason> = new Set<Reason>([
  "default",
  "domain_policy",
  "oauth_blocked",
  "expired",
]);

function parseReason(value: string | null): Reason {
  if (!value) return "default";
  return REASON_VALUES.has(value as Reason) ? (value as Reason) : "default";
}

const CONTENT: Record<Reason, { heading: string; body: string }> = {
  default: {
    heading: "Welcome",
    body: "Sign in with your enterprise account",
  },
  domain_policy: {
    heading: "SSO required",
    body: "Your organization requires single sign-on. Continue with your identity provider.",
  },
  oauth_blocked: {
    heading: "SSO required",
    body: "You can't use that provider to sign in — your organization requires SSO. Continue with your identity provider.",
  },
  expired: {
    heading: "Login attempt timed out",
    body: "Your SSO login attempt expired. Click Try again to restart.",
  },
};

const ERROR_MESSAGES: Record<string, string> = {
  missing_email: "Please enter your work email.",
  no_sso_for_domain:
    "We couldn't find an SSO configuration for that email's domain. Try a different login method.",
  no_org_for_domain: "We couldn't complete sign-in. Try again or contact your administrator.",
  no_active_connection: "Your organization doesn't have an active SSO connection yet.",
  feature_disabled: "SSO is not currently available.",
  rate_limited: "Too many SSO sign-in attempts. Please try again shortly.",
  sso_failed: "We couldn't complete sign-in. Try again.",
  missing_code: "We couldn't complete sign-in. Try again.",
};

// Client-side validation for the enterprise email field. The form posts
// cross-route to /auth/sso, so there's no same-route action result to hydrate
// from — conform validates the format in the browser and renders the styled
// inline error before submit. Server-side errors keep flowing via ?error=.
const ssoEmailSchema = z.object({
  email: z
    .string({ required_error: "Enter your enterprise email address" })
    .email("Enter a valid email address"),
});

export const meta: MetaFunction = () => [
  { title: "Sign in with SSO – Trigger.dev" },
  { name: "viewport", content: "width=device-width,initial-scale=1" },
];

export async function loader({ request }: LoaderFunctionArgs) {
  // Already-authenticated users have no business on the SSO form — bounce
  // them home, mirroring the /login/magic loader guard. Combined with
  // /login/sso being non-navigable, a crafted `?redirectTo=/login/sso`
  // can't strand a signed-in user here either.
  await authenticator.isAuthenticated(request, {
    successRedirect: "/",
  });

  const url = new URL(request.url);
  const reason = parseReason(url.searchParams.get("reason"));
  const email = url.searchParams.get("email") ?? "";
  const errorCode = url.searchParams.get("error");
  const redirectTo = url.searchParams.get("redirectTo") ?? "/";

  return typedjson({
    reason,
    email,
    redirectTo,
    errorMessage: errorCode
      ? (ERROR_MESSAGES[errorCode] ?? "We couldn't complete sign-in. Try again.")
      : null,
  });
}

export default function LoginSsoPage() {
  const { reason, email, redirectTo, errorMessage } = useTypedLoaderData<typeof loader>();
  const navigation = useNavigation();
  const isLoading =
    (navigation.state === "loading" || navigation.state === "submitting") &&
    navigation.formAction === "/auth/sso";

  const content = CONTENT[reason];
  const emailReadOnly = reason === "oauth_blocked";

  const [form, fields] = useForm({
    id: "login-sso",
    defaultValue: { email },
    onValidate({ formData }) {
      return parseWithZod(formData, { schema: ssoEmailSchema });
    },
    shouldValidate: "onSubmit",
    shouldRevalidate: "onInput",
  });

  return (
    <LoginPageLayout>
      <Form method="post" action="/auth/sso" {...getFormProps(form)}>
        <input type="hidden" name="redirectTo" value={redirectTo} />
        <input type="hidden" name="flow" value="user_initiated" />
        <div className="flex flex-col items-center justify-center">
          <Header1 className="pb-4 text-center font-semibold sm:text-2xl md:text-3xl lg:text-4xl">
            {content.heading}
          </Header1>
          <Paragraph variant="base" className="mb-6 text-center">
            {content.body}
          </Paragraph>
          <Fieldset className="flex w-full flex-col items-center gap-y-2">
            <InputGroup>
              <Input
                {...getInputProps(fields.email, { type: "email" })}
                spellCheck={false}
                placeholder="Enterprise email address"
                variant="large"
                autoFocus={!emailReadOnly}
                readOnly={emailReadOnly}
              />
              <FormError id={fields.email.errorId}>{fields.email.errors}</FormError>
            </InputGroup>

            <Button
              type="submit"
              variant="primary/large"
              disabled={isLoading}
              fullWidth
              data-action="continue with sso"
            >
              {isLoading && <Spinner className="mr-2 size-5" color="white" />}
              <span className="text-text-bright">
                {isLoading
                  ? "Redirecting…"
                  : reason === "expired"
                    ? "Try again"
                    : "Continue with SSO"}
              </span>
            </Button>

            {errorMessage && <FormError>{errorMessage}</FormError>}
          </Fieldset>

          <div className="mt-6 flex w-full items-center justify-between">
            <LinkButton
              to="/login"
              variant="minimal/small"
              LeadingIcon={ArrowLeftIcon}
              leadingIconClassName="text-text-dimmed group-hover:text-text-bright transition"
              data-action="all login options"
            >
              All login options
            </LinkButton>
            <LinkButton
              to="https://trigger.dev/contact"
              variant="minimal/small"
              TrailingIcon={ArrowUpRightIcon}
              trailingIconClassName="text-text-dimmed group-hover:text-text-bright transition"
              data-action="ask about sso"
            >
              Ask about SSO
            </LinkButton>
          </div>
        </div>
      </Form>
    </LoginPageLayout>
  );
}
