'use client';

import Image from 'next/image';
import { toast } from 'sonner';
import { useRouter } from 'next/navigation';
import { AnimatePresence, motion } from 'framer-motion';
import { Loader2, MailPlus, Edit, X } from 'lucide-react';
import { useState, useEffect, useTransition } from 'react';
import { ChevronDownIcon, PlusIcon } from '@radix-ui/react-icons';

import {
  Avatar,
  AvatarImage,
  AvatarFallback
} from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardHeader,
  CardTitle
} from '@/components/ui/card';
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger
} from '@/components/ui/dialog';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue
} from '@/components/ui/select';
import CopyButton from '@/components/ui/copy-button';
import {
  organization,
  useListOrganizations,
  useSession
} from '@/lib/auth/auth-client';
import { ActiveOrganization, Session } from '@/lib/auth/auth-types';

export function OrganizationCard(props: {
  session: Session | null;
  activeOrganization: ActiveOrganization | null;
}) {
  const organizations = useListOrganizations();
  const [optimisticOrg, setOptimisticOrg] = useState<ActiveOrganization | null>(
    props.activeOrganization
  );
  const [isRevoking, setIsRevoking] = useState<string[]>([]);
  const inviteVariants = {
    hidden: { opacity: 0, height: 0 },
    visible: { opacity: 1, height: 'auto' },
    exit: { opacity: 0, height: 0 }
  };

  const { data } = useSession();
  const session = data || props.session;

  const currentMember = optimisticOrg?.members?.find(
    (member) => member.userId === session?.user.id
  );

  return (
    <Card>
      <CardHeader>
        <CardTitle>Organization</CardTitle>
        <div className='flex justify-between'>
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <div className='flex cursor-pointer items-center gap-1'>
                <p className='text-sm'>
                  <span className='font-bold'></span>{' '}
                  {optimisticOrg?.name || 'Personal'}
                </p>

                <ChevronDownIcon />
              </div>
            </DropdownMenuTrigger>
            <DropdownMenuContent align='start'>
              <DropdownMenuItem
                className='py-1'
                onClick={async () => {
                  organization.setActive({
                    organizationId: null
                  });
                  setOptimisticOrg(null);
                }}
              >
                <p className='sm text-sm'>Personal</p>
              </DropdownMenuItem>
              {organizations.data?.map((org) => (
                <DropdownMenuItem
                  className='py-1'
                  key={org.id}
                  onClick={async () => {
                    if (org.id === optimisticOrg?.id) {
                      return;
                    }
                    setOptimisticOrg({
                      members: [],
                      invitations: [],
                      ...org
                    });
                    const { data } = await organization.setActive({
                      organizationId: org.id
                    });
                    setOptimisticOrg(data);
                  }}
                >
                  <p className='sm text-sm'>{org.name}</p>
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
          <div>
            <CreateOrganizationDialog />
          </div>
        </div>
        <div className='flex items-center gap-2'>
          <Avatar className='rounded-none'>
            <AvatarImage
              className='h-full w-full rounded-none object-cover'
              src={optimisticOrg?.logo || undefined}
            />
            <AvatarFallback className='rounded-none'>
              {optimisticOrg?.name?.charAt(0) || 'P'}
            </AvatarFallback>
          </Avatar>
          <div className='flex-1'>
            <div className='flex items-center gap-2'>
              <p>{optimisticOrg?.name || 'Personal'}</p>
              {optimisticOrg?.id && (
                <EditOrganizationDialog
                  optimisticOrg={optimisticOrg}
                  setOptimisticOrg={setOptimisticOrg}
                />
              )}
            </div>
            <p className='text-muted-foreground text-xs'>
              {optimisticOrg?.members?.length || 1} members
            </p>
          </div>
        </div>
      </CardHeader>
      <CardContent>
        <div className='flex flex-col gap-8 md:flex-row'>
          <div className='flex flex-grow flex-col gap-2'>
            <p className='border-b-foreground/10 border-b-2 font-medium'>
              Members
            </p>
            <div className='flex flex-col gap-2'>
              {optimisticOrg?.members?.map((member) => (
                <div
                  key={member.id}
                  className='flex items-center justify-between'
                >
                  <div className='flex items-center gap-2'>
                    <Avatar className='h-9 w-9 sm:flex'>
                      <AvatarImage
                        src={member.user.image || undefined}
                        className='object-cover'
                      />
                      <AvatarFallback>
                        {member.user.name?.charAt(0)}
                      </AvatarFallback>
                    </Avatar>
                    <div>
                      <p className='text-sm'>{member.user.name}</p>
                      <p className='text-muted-foreground text-xs'>
                        {member.role}
                      </p>
                    </div>
                  </div>
                  {member.role !== 'owner' &&
                    (currentMember?.role === 'owner' ||
                      currentMember?.role === 'admin') && (
                      <Button
                        size='sm'
                        variant='destructive'
                        onClick={() => {
                          organization.removeMember({
                            memberIdOrEmail: member.id
                          });
                        }}
                      >
                        {currentMember?.id === member.id ? 'Leave' : 'Remove'}
                      </Button>
                    )}
                </div>
              ))}
              {!optimisticOrg?.id && (
                <div>
                  <div className='flex items-center gap-2'>
                    <Avatar>
                      <AvatarImage src={session?.user.image || undefined} />
                      <AvatarFallback>
                        {session?.user.name?.charAt(0)}
                      </AvatarFallback>
                    </Avatar>
                    <div>
                      <p className='text-sm'>{session?.user.name}</p>
                      <p className='text-muted-foreground text-xs'>Owner</p>
                    </div>
                  </div>
                </div>
              )}
            </div>
          </div>
          <div className='flex flex-grow flex-col gap-2'>
            <p className='border-b-foreground/10 border-b-2 font-medium'>
              Invites
            </p>
            <div className='flex flex-col gap-2'>
              <AnimatePresence>
                {optimisticOrg?.invitations
                  ?.filter((invitation) => invitation.status === 'pending')
                  .map((invitation) => (
                    <motion.div
                      key={invitation.id}
                      className='flex items-center justify-between'
                      variants={inviteVariants}
                      initial='hidden'
                      animate='visible'
                      exit='exit'
                      layout
                    >
                      <div>
                        <p className='text-sm'>{invitation.email}</p>
                        <p className='text-muted-foreground text-xs'>
                          {invitation.role}
                        </p>
                      </div>
                      <div className='flex items-center gap-2'>
                        <Button
                          disabled={isRevoking.includes(invitation.id)}
                          size='sm'
                          variant='destructive'
                          onClick={() => {
                            organization.cancelInvitation(
                              {
                                invitationId: invitation.id
                              },
                              {
                                onRequest: () => {
                                  setIsRevoking([...isRevoking, invitation.id]);
                                },
                                onSuccess: () => {
                                  toast.message(
                                    'Invitation revoked successfully'
                                  );
                                  setIsRevoking(
                                    isRevoking.filter(
                                      (id) => id !== invitation.id
                                    )
                                  );
                                  setOptimisticOrg({
                                    ...optimisticOrg,
                                    invitations:
                                      optimisticOrg?.invitations?.filter(
                                        (inv) => inv.id !== invitation.id
                                      ) || []
                                  });
                                },
                                onError: (ctx) => {
                                  toast.error(ctx.error.message);
                                  setIsRevoking(
                                    isRevoking.filter(
                                      (id) => id !== invitation.id
                                    )
                                  );
                                }
                              }
                            );
                          }}
                        >
                          {isRevoking.includes(invitation.id) ? (
                            <Loader2 className='animate-spin' size={16} />
                          ) : (
                            'Revoke'
                          )}
                        </Button>
                        <div>
                          <CopyButton
                            textToCopy={`${window.location.origin}/accept-invitation/${invitation.id}`}
                          />
                        </div>
                      </div>
                    </motion.div>
                  ))}
              </AnimatePresence>
              {(optimisticOrg?.invitations?.length === 0 ||
                !optimisticOrg?.invitations) && (
                <motion.p
                  className='text-muted-foreground text-sm'
                  initial={{ opacity: 0 }}
                  animate={{ opacity: 1 }}
                  exit={{ opacity: 0 }}
                >
                  No Active Invitations
                </motion.p>
              )}
              {!optimisticOrg?.id && (
                <Label className='text-muted-foreground text-xs'>
                  You can&apos;t invite members to your personal workspace.
                </Label>
              )}
            </div>
          </div>
        </div>
        <div className='mt-4 flex w-full justify-end'>
          <div>
            <div>
              {optimisticOrg?.id && (
                <InviteMemberDialog
                  setOptimisticOrg={setOptimisticOrg}
                  optimisticOrg={optimisticOrg}
                />
              )}
            </div>
          </div>
        </div>
      </CardContent>
    </Card>
  );
}

function CreateOrganizationDialog() {
  const [name, setName] = useState('');
  const [slug, setSlug] = useState('');
  const [loading, setLoading] = useState(false);
  const [open, setOpen] = useState(false);
  const [isSlugEdited, setIsSlugEdited] = useState(false);
  const [logo, setLogo] = useState<string | null>(null);

  useEffect(() => {
    if (!isSlugEdited) {
      const generatedSlug = name.trim().toLowerCase().replace(/\s+/g, '-');
      setSlug(generatedSlug);
    }
  }, [name, isSlugEdited]);

  useEffect(() => {
    if (open) {
      setName('');
      setSlug('');
      setIsSlugEdited(false);
      setLogo(null);
    }
  }, [open]);

  const handleLogoChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files && e.target.files[0]) {
      const file = e.target.files[0];
      const reader = new FileReader();
      reader.onloadend = () => {
        setLogo(reader.result as string);
      };
      reader.readAsDataURL(file);
    }
  };

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button size='sm' className='w-full gap-2' variant='default'>
          <PlusIcon />
          <p>New Organization</p>
        </Button>
      </DialogTrigger>
      <DialogContent className='w-11/12 sm:max-w-[425px]'>
        <DialogHeader>
          <DialogTitle>New Organization</DialogTitle>
          <DialogDescription>
            Create a new organization to collaborate with your team.
          </DialogDescription>
        </DialogHeader>
        <div className='flex flex-col gap-4'>
          <div className='flex flex-col gap-2'>
            <Label>Organization Name</Label>
            <Input
              placeholder='Name'
              value={name}
              onChange={(e) => setName(e.target.value)}
            />
          </div>
          <div className='flex flex-col gap-2'>
            <Label>Organization Slug</Label>
            <Input
              value={slug}
              onChange={(e) => {
                setSlug(e.target.value);
                setIsSlugEdited(true);
              }}
              placeholder='Slug'
            />
          </div>
          <div className='flex flex-col gap-2'>
            <Label>Logo</Label>
            <Input type='file' accept='image/*' onChange={handleLogoChange} />
            {logo && (
              <div className='mt-2'>
                <Image
                  src={logo}
                  alt='Logo preview'
                  className='h-16 w-16 object-cover'
                  width={16}
                  height={16}
                />
              </div>
            )}
          </div>
        </div>
        <DialogFooter>
          <Button
            disabled={loading}
            onClick={async () => {
              setLoading(true);
              await organization.create(
                {
                  name: name,
                  slug: slug,
                  logo: logo || undefined
                },
                {
                  onResponse: () => {
                    setLoading(false);
                  },
                  onSuccess: () => {
                    toast.success('Organization created successfully');
                    setOpen(false);
                  },
                  onError: (error) => {
                    toast.error(error.error.message);
                    setLoading(false);
                  }
                }
              );
            }}
          >
            {loading ? (
              <Loader2 className='animate-spin' size={16} />
            ) : (
              'Create'
            )}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

function InviteMemberDialog({
  setOptimisticOrg,
  optimisticOrg
}: {
  setOptimisticOrg: (org: ActiveOrganization | null) => void;
  optimisticOrg: ActiveOrganization | null;
}) {
  const [email, setEmail] = useState('');
  const [role, setRole] = useState('member');
  const [loading, setLoading] = useState(false);
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button size='sm' className='w-full gap-2' variant='secondary'>
          <MailPlus size={16} />
          <p>Invite Member</p>
        </Button>
      </DialogTrigger>
      <DialogContent className='w-11/12 sm:max-w-[425px]'>
        <DialogHeader>
          <DialogTitle>Invite Member</DialogTitle>
          <DialogDescription>
            Invite a member to your organization.
          </DialogDescription>
        </DialogHeader>
        <div className='flex flex-col gap-2'>
          <Label>Email</Label>
          <Input
            placeholder='Email'
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <Label>Role</Label>
          <Select value={role} onValueChange={setRole}>
            <SelectTrigger>
              <SelectValue placeholder='Select a role' />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value='admin'>Admin</SelectItem>
              <SelectItem value='member'>Member</SelectItem>
            </SelectContent>
          </Select>
        </div>
        <DialogFooter>
          <DialogClose>
            <Button
              disabled={loading || !optimisticOrg?.id}
              onClick={async () => {
                if (!optimisticOrg?.id) {
                  toast.error('Select an organization before inviting members.');
                  return;
                }

                setLoading(true);
                try {
                  const response = await fetch('/api/organization/invitations', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                      organizationId: optimisticOrg.id,
                      email,
                      role
                    })
                  });

                  const payload = await response.json().catch(() => ({}));

                  if (!response.ok) {
                    throw new Error(
                      payload?.error || 'Unable to send invitation'
                    );
                  }

                  toast.success('Member invited successfully');
                  setLoading(false);
                  if (optimisticOrg) {
                    setOptimisticOrg({
                      ...optimisticOrg,
                      invitations: [
                        ...(optimisticOrg?.invitations || []),
                        payload?.data?.invitation
                      ].filter(Boolean)
                    });
                  }
                } catch (error) {
                  setLoading(false);
                  console.error('Failed to invite member:', error);
                  toast.error(
                    error instanceof Error
                      ? error.message
                      : 'Unable to send invitation'
                  );
                }
              }}
            >
              {loading ? <Loader2 className='animate-spin' size={16} /> : 'Invite'}
            </Button>
          </DialogClose>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

async function convertImageToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result as string);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

function EditOrganizationDialog({
  optimisticOrg,
  setOptimisticOrg
}: {
  optimisticOrg: ActiveOrganization;
  setOptimisticOrg: (org: ActiveOrganization | null) => void;
}) {
  const [name, setName] = useState<string>();
  const [logo, setLogo] = useState<File | null>(null);
  const [logoPreview, setLogoPreview] = useState<string | null>(null);
  const [open, setOpen] = useState<boolean>(false);
  const [isLoading, startTransition] = useTransition();
  const router = useRouter();

  const handleLogoChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      setLogo(file);
      const reader = new FileReader();
      reader.onloadend = () => {
        setLogoPreview(reader.result as string);
      };
      reader.readAsDataURL(file);
    }
  };

  const handleUpdate = async () => {
    startTransition(async () => {
      try {
        const updateData: { name?: string; logo?: string } = {};

        if (name && name.trim() !== optimisticOrg.name) {
          updateData.name = name.trim();
        }

        if (logo) {
          updateData.logo = await convertImageToBase64(logo);
        }

        if (Object.keys(updateData).length === 0) {
          toast.error('No changes to update');
          return;
        }

        await organization.update({
          organizationId: optimisticOrg.id,
          data: updateData,
          fetchOptions: {
            onSuccess: () => {
              toast.success('Organization updated successfully');
              // Update the optimistic state
              setOptimisticOrg({
                ...optimisticOrg,
                ...updateData
              });
              router.refresh();
              setOpen(false);
              setName('');
              setLogo(null);
              setLogoPreview(null);
            },
            onError: (error) => {
              toast.error(error.error.message);
            }
          }
        });
      } catch {
        toast.error('Failed to update organization');
      }
    });
  };

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button size='sm' variant='ghost' className='h-6 w-6 p-0'>
          <Edit size={12} />
        </Button>
      </DialogTrigger>
      <DialogContent className='w-11/12 sm:max-w-[425px]'>
        <DialogHeader>
          <DialogTitle>Edit Organization</DialogTitle>
          <DialogDescription>
            Update your organization information
          </DialogDescription>
        </DialogHeader>
        <div className='grid gap-4'>
          <div className='grid gap-2'>
            <Label htmlFor='name'>Organization Name</Label>
            <Input
              id='name'
              type='text'
              placeholder={optimisticOrg.name}
              value={name || ''}
              onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
                setName(e.target.value);
              }}
            />
          </div>
          <div className='grid gap-2'>
            <Label htmlFor='logo'>Organization Logo</Label>
            <div className='flex items-end gap-4'>
              {logoPreview ? (
                <div className='relative h-16 w-16 overflow-hidden rounded-sm'>
                  <Image
                    src={logoPreview}
                    alt='Logo preview'
                    layout='fill'
                    objectFit='cover'
                  />
                </div>
              ) : optimisticOrg.logo ? (
                <div className='relative h-16 w-16 overflow-hidden rounded-sm'>
                  <Image
                    src={optimisticOrg.logo}
                    alt='Current logo'
                    layout='fill'
                    objectFit='cover'
                  />
                </div>
              ) : null}
              <div className='flex w-full items-center gap-2'>
                <Input
                  id='logo'
                  type='file'
                  accept='image/*'
                  onChange={handleLogoChange}
                  className='text-muted-foreground w-full'
                />
                {logoPreview && (
                  <X
                    className='cursor-pointer'
                    size={16}
                    onClick={() => {
                      setLogo(null);
                      setLogoPreview(null);
                    }}
                  />
                )}
              </div>
            </div>
          </div>
        </div>
        <DialogFooter>
          <Button disabled={isLoading} onClick={handleUpdate}>
            {isLoading ? (
              <Loader2 size={15} className='animate-spin' />
            ) : (
              'Update'
            )}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
