import { TrashIcon } from "@heroicons/react/20/solid";
import { DialogClose } from "@radix-ui/react-dialog";
import type { LoaderFunctionArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { Form, useActionData, useNavigation } from "@remix-run/react";
import { fromPromise } from "neverthrow";
import { typedjson, useTypedLoaderData } from "remix-typedjson";
import { z } from "zod";
import { PageBody, PageContainer } from "~/components/layout/AppLayout";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "~/components/primitives/Dialog";
import { FormButtons } from "~/components/primitives/FormButtons";
import { Header1 } from "~/components/primitives/Headers";
import { Paragraph } from "~/components/primitives/Paragraph";
import {
  Table,
  TableBody,
  TableCell,
  TableHeader,
  TableHeaderCell,
  TableRow,
} from "~/components/primitives/Table";
import { $transaction, prisma } from "~/db.server";
import { resolveOrgIdFromSlug } from "~/models/organization.server";
import { VercelIntegrationRepository } from "~/models/vercelIntegration.server";
import { logger } from "~/services/logger.server";
import { requireOrganization } from "~/services/org.server";
import { rbac } from "~/services/rbac.server";
import { dashboardAction } from "~/services/routeBuilders/dashboardBuilder";
import { OrganizationParamsSchema, v3ProjectSettingsIntegrationsPath } from "~/utils/pathBuilder";

function formatDate(date: Date): string {
  return new Intl.DateTimeFormat("en-US", {
    month: "short",
    day: "numeric",
    year: "numeric",
    hour: "numeric",
    minute: "2-digit",
    second: "2-digit",
    hour12: true,
  }).format(date);
}

export const loader = async ({ request, params }: LoaderFunctionArgs) => {
  const { organizationSlug } = OrganizationParamsSchema.parse(params);
  const url = new URL(request.url);
  const configurationId = url.searchParams.get("configurationId") ?? undefined;
  const { organization, userId } = await requireOrganization(request, organizationSlug);

  // Display flag for the Remove Integration control — the action enforces
  // write:vercel independently. Permissive in OSS.
  const sessionAuth = await rbac.authenticateSession(request, {
    userId,
    organizationId: organization.id,
  });
  const canManageVercel = sessionAuth.ok
    ? sessionAuth.ability.can("write", { type: "vercel" })
    : true;

  // Find Vercel integration for this organization
  let vercelIntegration = await prisma.organizationIntegration.findFirst({
    where: {
      organizationId: organization.id,
      service: "VERCEL",
      deletedAt: null,
      // If configurationId is provided, filter by it in integrationData
      ...(configurationId && {
        integrationData: {
          path: ["installationId"],
          equals: configurationId,
        },
      }),
    },
    include: {
      tokenReference: true,
    },
  });

  if (!vercelIntegration) {
    return typedjson({
      organization,
      vercelIntegration: null,
      connectedProjects: [],
      teamId: null,
      installationId: null,
      canManageVercel,
    });
  }

  // Get team ID from integrationData
  const integrationData = vercelIntegration.integrationData as any;
  const teamId = integrationData?.teamId ?? null;
  const installationId = integrationData?.installationId ?? null;

  // Get all connected projects for this integration
  const connectedProjects = await prisma.organizationProjectIntegration.findMany({
    where: {
      organizationIntegrationId: vercelIntegration.id,
      deletedAt: null,
    },
    include: {
      project: {
        select: {
          id: true,
          slug: true,
          name: true,
        },
      },
    },
    orderBy: {
      createdAt: "desc",
    },
  });

  return typedjson({
    organization,
    vercelIntegration,
    connectedProjects,
    teamId,
    installationId,
    canManageVercel,
  });
};

const ActionSchema = z.object({
  intent: z.literal("uninstall"),
});

export const action = dashboardAction(
  {
    params: OrganizationParamsSchema,
    context: async (params) => {
      const organizationId = await resolveOrgIdFromSlug(params.organizationSlug);
      return organizationId ? { organizationId } : {};
    },
    authorization: { action: "write", resource: { type: "vercel" } },
  },
  async ({ request, params }) => {
    const { organizationSlug } = params;
    const { organization, userId } = await requireOrganization(request, organizationSlug);

    const formData = await request.formData();
    const result = ActionSchema.safeParse({ intent: formData.get("intent") });
    if (!result.success) {
      return json({ error: "Invalid action" }, { status: 400 });
    }

    // Find Vercel integration
    const vercelIntegration = await prisma.organizationIntegration.findFirst({
      where: {
        organizationId: organization.id,
        service: "VERCEL",
        deletedAt: null,
      },
      include: {
        tokenReference: true,
      },
    });

    if (!vercelIntegration) {
      return json({ error: "Vercel integration not found" }, { status: 404 });
    }

    // Uninstall from Vercel side
    const uninstallResult =
      await VercelIntegrationRepository.uninstallVercelIntegration(vercelIntegration);

    if (uninstallResult.isErr()) {
      logger.error("Failed to uninstall Vercel integration", {
        organizationId: organization.id,
        organizationSlug,
        userId,
        integrationId: vercelIntegration.id,
        error: uninstallResult.error.message,
      });

      return json(
        { error: "Failed to uninstall Vercel integration. Please try again." },
        { status: 500 }
      );
    }

    // Soft-delete the integration and all connected projects in a transaction
    const txResult = await fromPromise(
      $transaction(prisma, async (tx) => {
        await tx.organizationProjectIntegration.updateMany({
          where: {
            organizationIntegrationId: vercelIntegration.id,
            deletedAt: null,
          },
          data: { deletedAt: new Date() },
        });

        await tx.organizationIntegration.update({
          where: { id: vercelIntegration.id },
          data: { deletedAt: new Date() },
        });
      }),
      (error) => error
    );

    if (txResult.isErr()) {
      logger.error("Failed to soft-delete Vercel integration records", {
        organizationId: organization.id,
        organizationSlug,
        userId,
        integrationId: vercelIntegration.id,
        error: txResult.error instanceof Error ? txResult.error.message : String(txResult.error),
      });

      return json(
        { error: "Failed to uninstall Vercel integration. Please try again." },
        { status: 500 }
      );
    }

    if (uninstallResult.value.authInvalid) {
      logger.warn("Vercel integration uninstalled with auth error - token invalid", {
        organizationId: organization.id,
        organizationSlug,
        userId,
        integrationId: vercelIntegration.id,
      });
    } else {
      logger.info("Vercel integration uninstalled successfully", {
        organizationId: organization.id,
        organizationSlug,
        userId,
        integrationId: vercelIntegration.id,
      });
    }

    // Redirect back to organization settings
    return redirect(`/orgs/${organizationSlug}/settings`);
  }
);

export default function VercelIntegrationPage() {
  const {
    organization,
    vercelIntegration,
    connectedProjects,
    teamId,
    installationId,
    canManageVercel,
  } = useTypedLoaderData<typeof loader>();
  const actionData = useActionData<typeof action>();
  const navigation = useNavigation();
  const isUninstalling =
    navigation.state === "submitting" && navigation.formData?.get("intent") === "uninstall";

  if (!vercelIntegration) {
    return (
      <PageContainer>
        <PageBody>
          <div className="flex flex-col items-center justify-center py-8">
            <Header1>No Vercel Integration Found</Header1>
            <Paragraph className="mt-2 text-center text-text-dimmed">
              This organization doesn't have a Vercel integration configured.
            </Paragraph>
          </div>
        </PageBody>
      </PageContainer>
    );
  }

  return (
    <PageContainer>
      <PageBody>
        <div className="mb-8">
          <Header1>Vercel Integration</Header1>
          <Paragraph className="mt-2 text-text-dimmed">
            Manage your organization's Vercel integration and connected projects.
          </Paragraph>
        </div>

        {/* Integration Info Section */}
        <div className="mb-8 rounded-lg border border-grid-bright bg-background-bright p-6">
          <div className="flex items-center justify-between">
            <div>
              <h2 className="text-lg font-medium text-text-bright">Integration Details</h2>
              <div className="mt-2 space-y-1 text-sm text-text-dimmed">
                {teamId && (
                  <div>
                    <span className="font-medium">Vercel Team ID:</span> {teamId}
                  </div>
                )}
                {installationId && (
                  <div>
                    <span className="font-medium">Installation ID:</span> {installationId}
                  </div>
                )}
                <div>
                  <span className="font-medium">Installed:</span>{" "}
                  {formatDate(new Date(vercelIntegration.createdAt))}
                </div>
              </div>
            </div>
            <div className="flex flex-col items-end gap-2">
              <Dialog>
                <DialogTrigger asChild>
                  <Button
                    variant="danger/medium"
                    LeadingIcon={TrashIcon}
                    disabled={isUninstalling || !canManageVercel}
                    tooltip={
                      canManageVercel
                        ? undefined
                        : "You don't have permission to manage the Vercel integration"
                    }
                  >
                    Remove Integration
                  </Button>
                </DialogTrigger>
                <DialogContent>
                  <DialogHeader>
                    <DialogTitle>Remove Vercel Integration</DialogTitle>
                  </DialogHeader>
                  <DialogDescription>
                    This will permanently remove the Vercel integration and disconnect all projects.
                    This action cannot be undone.
                  </DialogDescription>
                  <FormButtons
                    confirmButton={
                      <Form method="post">
                        <input type="hidden" name="intent" value="uninstall" />
                        <Button
                          variant="danger/medium"
                          LeadingIcon={TrashIcon}
                          type="submit"
                          disabled={isUninstalling}
                        >
                          {isUninstalling ? "Removing..." : "Remove Integration"}
                        </Button>
                      </Form>
                    }
                    cancelButton={
                      <DialogClose asChild>
                        <Button variant="tertiary/medium">Cancel</Button>
                      </DialogClose>
                    }
                  />
                </DialogContent>
              </Dialog>
              {actionData?.error && (
                <Paragraph variant="small" className="text-error">
                  {actionData.error}
                </Paragraph>
              )}
            </div>
          </div>
        </div>

        {/* Connected Projects Section */}
        <div>
          <h2 className="mb-4 text-lg font-medium text-text-bright">
            Connected Projects ({connectedProjects.length})
          </h2>

          {connectedProjects.length === 0 ? (
            <div className="rounded-lg border border-grid-bright bg-background-bright p-6 text-center">
              <Paragraph className="text-text-dimmed">
                No projects are currently connected to this Vercel integration.
              </Paragraph>
            </div>
          ) : (
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHeaderCell>Project Name</TableHeaderCell>
                  <TableHeaderCell>Vercel Project ID</TableHeaderCell>
                  <TableHeaderCell>Connected</TableHeaderCell>
                  <TableHeaderCell hiddenLabel>Actions</TableHeaderCell>
                </TableRow>
              </TableHeader>
              <TableBody>
                {connectedProjects.map((projectIntegration) => (
                  <TableRow key={projectIntegration.id}>
                    <TableCell>{projectIntegration.project.name}</TableCell>
                    <TableCell className="font-mono text-xs">
                      {projectIntegration.externalEntityId}
                    </TableCell>
                    <TableCell>{formatDate(new Date(projectIntegration.createdAt))}</TableCell>
                    <TableCell>
                      <LinkButton
                        variant="minimal/small"
                        to={v3ProjectSettingsIntegrationsPath(
                          organization,
                          projectIntegration.project,
                          { slug: "prod" } // Default to production environment
                        )}
                      >
                        Configure
                      </LinkButton>
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          )}
        </div>
      </PageBody>
    </PageContainer>
  );
}
