import DotIcon from '@/components/icons/dot-icon';
import LoaderIcon from '@/components/icons/loader-icon';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Separator } from '@/components/ui/separator';
import { Textarea } from '@/components/ui/textarea';
import { sendTicketReply } from '@/data/admin/ticket/send-ticket-reply';
import { updateRequest } from '@/data/request/update-request';
import { useInitials } from '@/hooks/use-initials';
import { useApiSWR } from '@/hooks/useSWR';
import { SharedData } from '@/types';
import {
  TTicketDetails,
  TTicketReply,
} from '@/types/admin/support-ticket-type';
import { getImageUrl } from '@/utils/getImageUrl';
import { zodResolver } from '@hookform/resolvers/zod';
import { usePage } from '@inertiajs/react';
import {
  CaretDownIcon,
  ChatsCircleIcon,
  CheckIcon,
  PaperclipIcon,
  XIcon,
} from '@phosphor-icons/react';
import dayjs from 'dayjs';
import { useCallback, useRef, useState, useTransition } from 'react';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';
import z from 'zod';

const STATUS_OPTIONS = [
  { value: 'open', label: 'Open' },
  { value: 'closed', label: 'Closed' },
  { value: 'pending', label: 'Pending' },
] as const;

const PRIORITY_OPTIONS = [
  { value: 'low', label: 'Low' },
  { value: 'medium', label: 'Medium' },
  { value: 'high', label: 'High' },
] as const;

const ReplySchema = z
  .object({
    message: z.string(),
    attachments: z.array(z.instanceof(File)).optional(),
  })
  .refine(
    (data) =>
      data.message.trim().length > 0 ||
      (data.attachments && data.attachments.length > 0),
    {
      message: 'Message or attachment is required',
      path: ['message'],
    },
  );

type ReplyForm = z.infer<typeof ReplySchema>;

export default function ChatBox({ ticketId }: { ticketId: number | null }) {
  const getInitials = useInitials();
  const page = usePage<SharedData>();
  const { auth } = page.props;
  const currentUser = auth.user;

  const {
    data: ticket,
    isLoading,
    mutate,
  } = useApiSWR<TTicketDetails>(
    ticketId && !isNaN(ticketId) ? `/admin/tickets/${ticketId}` : '',
  );
  const [isPending, startTransition] = useTransition();
  const [attachments, setAttachments] = useState<File[]>([]);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const messagesContainerRef = useRef<HTMLDivElement>(null);
  const { t } = useTranslation();

  const form = useForm<ReplyForm>({
    resolver: zodResolver(ReplySchema),
    defaultValues: {
      message: '',
      attachments: [],
    },
  });

  const handleSubmit = useCallback(
    (data: ReplyForm) => {
      startTransition(async () => {
        const res = await sendTicketReply({
          id: ticketId as number,
          message: data.message.trim() || '',
          attachments: attachments.length > 0 ? attachments : undefined,
        });

        if (res?.success) {
          toast.success(t(res?.message));
          form.reset();
          setAttachments([]);
          const el = document.getElementById('attachments') as HTMLInputElement;
          if (el) el.value = '';
          mutate();
        } else {
          toast.error(t(res?.error ?? 'Failed to send reply'));
        }
      });
    },
    [ticketId, attachments, form, mutate, t],
  );

  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files?.length) {
      setAttachments((prev) => [...prev, ...Array.from(e.target.files!)]);
    }
  };

  const handleAttachmentClick = () => {
    const el = document.getElementById('attachments') as HTMLInputElement;
    el?.click();
  };

  const removeAttachment = (index: number) => {
    setAttachments((prev) => prev.filter((_, i) => i !== index));
  };

  const handleStatusChange = (id: number, status: string, priority: string) => {
    toast.promise(
      updateRequest({
        url: `/api/admin/tickets/${id}/status`,
        formData: { status, priority },
      }),
      {
        loading: t('Updating...'),
        success: (res) => {
          if (!res.message) throw new Error(res.message);
          mutate();
          return res.message;
        },
        error: t('Failed to update'),
      },
    );
  };

  const handleVariant = (status: string) => {
    switch (status) {
      case 'open':
        return 'outlineSuccess';
      case 'low':
        return 'outlineSuccess';
      case 'closed':
        return 'outlineDestructive';
      case 'high':
        return 'outlineDestructive';
      case 'pending':
        return 'outlineWarning';
      case 'medium':
        return 'outlineWarning';
      default:
        return 'outline';
    }
  };

  if (isLoading)
    return (
      <div className="flex flex-1 items-center justify-center gap-2 rounded-xl bg-white p-6 shadow-box">
        <LoaderIcon />
        {t('Loading...')}
      </div>
    );

  if (!ticketId)
    return (
      <div className="hidden flex-1 flex-col rounded-xl bg-white p-6 shadow-box md:flex">
        <div className="flex h-full flex-col items-center justify-center text-center">
          <ChatsCircleIcon
            weight="fill"
            className="mb-2 size-14 text-black/60"
          />
          <h3 className="mb-1 text-xl font-medium">
            {t('No conversation selected')}
          </h3>
          <p className="text-sm text-black/50">
            {t('Choose a conversation from the list to continue')}
          </p>
        </div>
      </div>
    );

  if (!ticket) return null;

  return (
    <div className="flex flex-1 flex-col rounded-xl bg-white p-4 shadow-box md:p-6">
      <div className="flex flex-wrap items-center justify-between gap-2">
        <div className="flex min-w-0 items-center gap-4">
          <Avatar className="size-10 shrink-0 overflow-hidden rounded-full">
            <AvatarImage
              src={getImageUrl(ticket?.user?.profile?.profile_photo)}
              alt={[ticket?.user?.first_name, ticket?.user?.last_name]
                .filter(Boolean)
                .join(' ')}
            />
            <AvatarFallback className="rounded-lg bg-neutral-200 font-medium text-black dark:bg-neutral-700 dark:text-white">
              {getInitials(
                [ticket?.user?.first_name, ticket?.user?.last_name]
                  .filter(Boolean)
                  .join(' '),
              )}
            </AvatarFallback>
          </Avatar>
          <div className="min-w-0">
            <p className="truncate">
              {ticket.subject}
              {' #'}
              {ticket.id}
            </p>
            <div className="flex min-w-0 flex-wrap items-center gap-1">
              <p className="truncate text-sm text-black/50">
                {[ticket?.user?.first_name, ticket?.user?.last_name]
                  .filter(Boolean)
                  .join(' ')}
              </p>
              <DotIcon />
              <p className="truncate text-sm text-black/50">
                {ticket?.user?.email}
              </p>
            </div>
          </div>
        </div>
        <div className="flex shrink-0 items-center gap-2">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                variant={handleVariant(ticket.status)}
                className="w-28 justify-between capitalize md:w-32"
              >
                {t(ticket.status)}
                <CaretDownIcon weight="bold" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent>
              {STATUS_OPTIONS.map((opt) => (
                <DropdownMenuItem
                  key={opt.value}
                  onClick={() =>
                    handleStatusChange(ticket.id, opt.value, ticket.priority)
                  }
                >
                  {t(opt.label)}
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                variant={handleVariant(ticket.priority)}
                className="w-28 justify-between capitalize md:w-32"
              >
                {t(ticket.priority)}
                <CaretDownIcon weight="bold" />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent>
              {PRIORITY_OPTIONS.map((opt) => (
                <DropdownMenuItem
                  key={opt.value}
                  onClick={() =>
                    handleStatusChange(ticket.id, ticket.status, opt.value)
                  }
                >
                  {t(opt.label)}
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </div>
      <Separator className="my-4" />

      <div
        ref={messagesContainerRef}
        className="flex flex-1 flex-col-reverse space-y-2 overflow-y-auto p-4"
      >
        {ticket.ticket_replies?.slice().map((reply: TTicketReply) => {
          const replyUser = reply.user;
          const isCurrentUser = replyUser?.id === currentUser?.id;

          return (
            <div
              key={reply.id}
              className={`flex flex-col ${isCurrentUser ? 'items-end' : 'items-start'}`}
            >
              <div
                className={`max-w-[70%] rounded-2xl bg-secondary p-4 ${
                  isCurrentUser
                    ? 'bg-primary text-primary-foreground'
                    : 'bg-secondary'
                }`}
              >
                <p className="text-sm">{reply.message}</p>
                <p className="mt-2 text-xs text-black/50">
                  {dayjs(reply.created_at).format('h:mm A, MMM D, YYYY')}
                </p>
              </div>
              {reply.ticket_attachments &&
                reply.ticket_attachments.length > 0 && (
                  <div className="mt-1 flex flex-col gap-1">
                    {reply.ticket_attachments.map(
                      (attachment: { id: number; file: string }) => (
                        <img
                          key={attachment.id}
                          src={getImageUrl(attachment?.file)}
                          alt={t('Attached image')}
                        />
                      ),
                    )}
                  </div>
                )}
            </div>
          );
        })}
        <div ref={messagesEndRef} />
      </div>

      <Form {...form}>
        <form
          onSubmit={form.handleSubmit(handleSubmit)}
          className="space-y-3 pt-4"
        >
          <FormField
            control={form.control}
            name="message"
            render={({ field }) => (
              <FormItem>
                <FormControl>
                  <Textarea
                    placeholder={t('Write your message here...')}
                    className="min-h-20 resize-none"
                    {...field}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <div className="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
            <div className="flex flex-wrap items-start gap-2">
              {attachments.length > 0 &&
                attachments.map((file, index) => (
                  <span
                    key={`${file.name}-${index}`}
                    className="inline-flex items-center gap-1 rounded-md bg-secondary px-2 py-1 text-xs"
                  >
                    {file.name}
                    <button
                      type="button"
                      onClick={() => removeAttachment(index)}
                      className="ml-1 cursor-pointer rounded hover:bg-black/10"
                      aria-label="Remove file"
                    >
                      <XIcon />
                    </button>
                  </span>
                ))}
            </div>
            <div className="flex shrink-0 justify-end gap-2">
              <Input
                type="file"
                multiple
                tabIndex={1}
                onChange={handleFileChange}
                className="hidden"
                id="attachments"
              />
              <Button
                type="button"
                variant="secondary"
                onClick={handleAttachmentClick}
              >
                <div>
                  <PaperclipIcon size={16} />
                </div>
                {t('Attach File')}
              </Button>
              <Button
                type="submit"
                tabIndex={2}
                loading={isPending}
                disabled={isPending}
              >
                {t('Send')}
                <CheckIcon weight="bold" />
              </Button>
            </div>
          </div>
        </form>
      </Form>
    </div>
  );
}
