"use client";

import { api } from "~/trpc/react";
import { Spinner } from "@unsend/ui/src/spinner";
import { Button } from "@unsend/ui/src/button";
import { Input } from "@unsend/ui/src/input";
import { Editor } from "@unsend/email-editor";
import { useState } from "react";
import { Campaign } from "@prisma/client";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
} from "@unsend/ui/src/select";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@unsend/ui/src/dialog";
import { z } from "zod";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@unsend/ui/src/form";
import { toast } from "@unsend/ui/src/toaster";
import { useDebouncedCallback } from "use-debounce";
import { formatDistanceToNow } from "date-fns";
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@unsend/ui/src/accordion";

const sendSchema = z.object({
  confirmation: z.string(),
});

const IMAGE_SIZE_LIMIT = 10 * 1024 * 1024;

export default function EditCampaignPage({
  params,
}: {
  params: { campaignId: string };
}) {
  const {
    data: campaign,
    isLoading,
    error,
  } = api.campaign.getCampaign.useQuery(
    { campaignId: params.campaignId },
    {
      enabled: !!params.campaignId,
    }
  );

  if (isLoading) {
    return (
      <div className="flex justify-center items-center h-full">
        <Spinner className="w-6 h-6" />
      </div>
    );
  }

  if (error) {
    return (
      <div className="flex justify-center items-center h-full">
        <p className="text-red-500">Failed to load campaign</p>
      </div>
    );
  }

  if (!campaign) {
    return <div>Campaign not found</div>;
  }

  return <CampaignEditor campaign={campaign} />;
}

function CampaignEditor({
  campaign,
}: {
  campaign: Campaign & { imageUploadSupported: boolean };
}) {
  const contactBooksQuery = api.contacts.getContactBooks.useQuery();
  const utils = api.useUtils();

  const [json, setJson] = useState<Record<string, any> | undefined>(
    campaign.content ? JSON.parse(campaign.content) : undefined
  );
  const [isSaving, setIsSaving] = useState(false);
  const [name, setName] = useState(campaign.name);
  const [subject, setSubject] = useState(campaign.subject);
  const [from, setFrom] = useState(campaign.from);
  const [contactBookId, setContactBookId] = useState(campaign.contactBookId);
  const [replyTo, setReplyTo] = useState<string | undefined>(
    campaign.replyTo[0]
  );
  const [previewText, setPreviewText] = useState<string | null>(
    campaign.previewText
  );
  const [openSendDialog, setOpenSendDialog] = useState(false);

  const updateCampaignMutation = api.campaign.updateCampaign.useMutation({
    onSuccess: () => {
      utils.campaign.getCampaign.invalidate();
      setIsSaving(false);
    },
  });
  const sendCampaignMutation = api.campaign.sendCampaign.useMutation();
  const getUploadUrl = api.campaign.generateImagePresignedUrl.useMutation();

  const sendForm = useForm<z.infer<typeof sendSchema>>({
    resolver: zodResolver(sendSchema),
  });

  function updateEditorContent() {
    updateCampaignMutation.mutate({
      campaignId: campaign.id,
      content: JSON.stringify(json),
    });
  }

  const deboucedUpdateCampaign = useDebouncedCallback(
    updateEditorContent,
    1000
  );

  async function onSendCampaign(values: z.infer<typeof sendSchema>) {
    if (
      values.confirmation?.toLocaleLowerCase() !== "Send".toLocaleLowerCase()
    ) {
      sendForm.setError("confirmation", {
        message: "Please type 'Send' to confirm",
      });
      return;
    }

    sendCampaignMutation.mutate(
      {
        campaignId: campaign.id,
      },
      {
        onSuccess: () => {
          setOpenSendDialog(false);
          toast.success(`Campaign sent successfully`);
        },
        onError: (error) => {
          toast.error(`Failed to send campaign: ${error.message}`);
        },
      }
    );
  }

  const handleFileChange = async (file: File) => {
    if (file.size > IMAGE_SIZE_LIMIT) {
      throw new Error(
        `File should be less than ${IMAGE_SIZE_LIMIT / 1024 / 1024}MB`
      );
    }

    console.log("file type: ", file.type);

    const { uploadUrl, imageUrl } = await getUploadUrl.mutateAsync({
      name: file.name,
      type: file.type,
      campaignId: campaign.id,
    });

    const response = await fetch(uploadUrl, {
      method: "PUT",
      body: file,
    });

    if (!response.ok) {
      throw new Error("Failed to upload file");
    }

    return imageUrl;
  };

  const confirmation = sendForm.watch("confirmation");

  const contactBook = contactBooksQuery.data?.find(
    (book) => book.id === contactBookId
  );

  return (
    <div className="p-4 container mx-auto ">
      <div className="mx-auto">
        <div className="mb-4 flex justify-between items-center w-[700px] mx-auto">
          <Input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
            className=" border-0 focus:ring-0 focus:outline-none px-0.5 w-[300px]"
            onBlur={() => {
              if (name === campaign.name || !name) {
                return;
              }
              updateCampaignMutation.mutate(
                {
                  campaignId: campaign.id,
                  name,
                },
                {
                  onError: (e) => {
                    toast.error(`${e.message}. Reverting changes.`);
                    setName(campaign.name);
                  },
                }
              );
            }}
          />
          <div className="flex items-center gap-4">
            <div className="flex items-center gap-2 text-sm text-gray-500">
              {isSaving ? (
                <div className="h-2 w-2 bg-yellow-500 rounded-full" />
              ) : (
                <div className="h-2 w-2 bg-emerald-500 rounded-full" />
              )}
              {formatDistanceToNow(campaign.updatedAt) === "less than a minute"
                ? "just now"
                : `${formatDistanceToNow(campaign.updatedAt)} ago`}
            </div>
            <Dialog open={openSendDialog} onOpenChange={setOpenSendDialog}>
              <DialogTrigger asChild>
                <Button variant="default">Send Campaign</Button>
              </DialogTrigger>
              <DialogContent>
                <DialogHeader>
                  <DialogTitle>Send Campaign</DialogTitle>
                  <DialogDescription>
                    Are you sure you want to send this campaign? This action
                    cannot be undone.
                  </DialogDescription>
                </DialogHeader>
                <div className="py-2">
                  <Form {...sendForm}>
                    <form
                      onSubmit={sendForm.handleSubmit(onSendCampaign)}
                      className="space-y-4"
                    >
                      <FormField
                        control={sendForm.control}
                        name="confirmation"
                        render={({ field }) => (
                          <FormItem>
                            <FormLabel>Type 'Send' to confirm</FormLabel>
                            <FormControl>
                              <Input {...field} />
                            </FormControl>
                            <FormMessage />
                          </FormItem>
                        )}
                      />
                      <div className="flex justify-end">
                        <Button
                          type="submit"
                          disabled={
                            sendCampaignMutation.isPending ||
                            confirmation?.toLocaleLowerCase() !==
                              "Send".toLocaleLowerCase()
                          }
                        >
                          {sendCampaignMutation.isPending
                            ? "Sending..."
                            : "Send"}
                        </Button>
                      </div>
                    </form>
                  </Form>
                </div>
              </DialogContent>
            </Dialog>
          </div>
        </div>

        <Accordion type="single" collapsible>
          <AccordionItem value="item-1">
            <div className="flex flex-col border shadow rounded-lg mt-12 mb-12 p-4 w-[700px] mx-auto z-50">
              <div className="flex items-center gap-4">
                <label className="block text-sm  w-[80px] text-muted-foreground">
                  Subject
                </label>
                <input
                  type="text"
                  value={subject}
                  onChange={(e) => {
                    setSubject(e.target.value);
                  }}
                  onBlur={() => {
                    if (subject === campaign.subject || !subject) {
                      return;
                    }
                    updateCampaignMutation.mutate(
                      {
                        campaignId: campaign.id,
                        subject,
                      },
                      {
                        onError: (e) => {
                          toast.error(`${e.message}. Reverting changes.`);
                          setSubject(campaign.subject);
                        },
                      }
                    );
                  }}
                  className="mt-1 py-1 text-sm block w-full outline-none border-b border-transparent  focus:border-border bg-transparent"
                />
                <AccordionTrigger className="py-0"></AccordionTrigger>
              </div>

              <AccordionContent className=" flex flex-col gap-4">
                <div className=" flex items-center gap-4 mt-4">
                  <label className=" text-sm  w-[80px] text-muted-foreground">
                    From
                  </label>
                  <input
                    type="text"
                    value={from}
                    onChange={(e) => {
                      setFrom(e.target.value);
                    }}
                    className="mt-1 py-1 w-full text-sm outline-none border-b border-transparent  focus:border-border bg-transparent"
                    placeholder="Friendly name<hello@example.com>"
                    onBlur={() => {
                      if (from === campaign.from || !from) {
                        return;
                      }
                      updateCampaignMutation.mutate(
                        {
                          campaignId: campaign.id,
                          from,
                        },
                        {
                          onError: (e) => {
                            toast.error(`${e.message}. Reverting changes.`);
                            setFrom(campaign.from);
                          },
                        }
                      );
                    }}
                  />
                </div>
                <div className="flex items-center gap-4">
                  <label className="block text-sm  w-[80px] text-muted-foreground">
                    Reply To
                  </label>
                  <input
                    type="text"
                    value={replyTo}
                    onChange={(e) => {
                      setReplyTo(e.target.value);
                    }}
                    className="mt-1 py-1 text-sm block w-full outline-none border-b border-transparent bg-transparent focus:border-border"
                    placeholder="hello@example.com"
                    onBlur={() => {
                      if (replyTo === campaign.replyTo[0]) {
                        return;
                      }
                      updateCampaignMutation.mutate(
                        {
                          campaignId: campaign.id,
                          replyTo: replyTo ? [replyTo] : [],
                        },
                        {
                          onError: (e) => {
                            toast.error(`${e.message}. Reverting changes.`);
                            setReplyTo(campaign.replyTo[0]);
                          },
                        }
                      );
                    }}
                  />
                </div>

                <div className="flex items-center gap-4">
                  <label className="block text-sm  w-[80px] text-muted-foreground">
                    Preview
                  </label>
                  <input
                    type="text"
                    value={previewText ?? undefined}
                    onChange={(e) => {
                      setPreviewText(e.target.value);
                    }}
                    onBlur={() => {
                      if (
                        previewText === campaign.previewText ||
                        !previewText
                      ) {
                        return;
                      }
                      updateCampaignMutation.mutate(
                        {
                          campaignId: campaign.id,
                          previewText,
                        },
                        {
                          onError: (e) => {
                            toast.error(`${e.message}. Reverting changes.`);
                            setPreviewText(campaign.previewText ?? "");
                          },
                        }
                      );
                    }}
                    className="mt-1 py-1 text-sm block w-full outline-none border-b border-transparent bg-transparent  focus:border-border"
                  />
                </div>
                <div className=" flex items-center gap-2">
                  <label className="block text-sm  w-[80px] text-muted-foreground">
                    To
                  </label>
                  {contactBooksQuery.isLoading ? (
                    <Spinner className="w-6 h-6" />
                  ) : (
                    <Select
                      value={contactBookId ?? ""}
                      onValueChange={(val) => {
                        // Update the campaign's contactBookId
                        updateCampaignMutation.mutate(
                          {
                            campaignId: campaign.id,
                            contactBookId: val,
                          },
                          {
                            onError: () => {
                              setContactBookId(campaign.contactBookId);
                            },
                          }
                        );
                        setContactBookId(val);
                      }}
                    >
                      <SelectTrigger className="w-[300px]">
                        {contactBook
                          ? `${contactBook.emoji} ${contactBook.name}`
                          : "Select a contact book"}
                      </SelectTrigger>
                      <SelectContent>
                        {contactBooksQuery.data?.map((book) => (
                          <SelectItem key={book.id} value={book.id}>
                            {book.emoji} {book.name}{" "}
                            <span className="text-xs text-muted-foreground ml-4">
                              {" "}
                              {book._count.contacts} contacts
                            </span>
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                  )}
                </div>
              </AccordionContent>
            </div>
          </AccordionItem>
        </Accordion>

        <div className=" rounded-lg bg-gray-50 w-[700px] mx-auto p-10">
          <div className="w-[600px] mx-auto">
            <Editor
              initialContent={json}
              onUpdate={(content) => {
                setJson(content.getJSON());
                setIsSaving(true);
                deboucedUpdateCampaign();
              }}
              variables={["email", "firstName", "lastName"]}
              uploadImage={
                campaign.imageUploadSupported ? handleFileChange : undefined
              }
            />
          </div>
        </div>
      </div>
    </div>
  );
}
