import PageHeading from '@/components/common/page-heading';
import LoaderIcon from '@/components/icons/loader-icon';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
import { givePermission } from '@/data/admin/permission/give-permission';
import { revokePermission } from '@/data/admin/permission/revoke-permission';
import { useApiSWR } from '@/hooks/useSWR';
import { THasPermission, TPermission } from '@/types/admin/staff-type';
import { usePage } from '@inertiajs/react';
import { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';

const groupByType = (permissions: TPermission[]) => {
  return permissions.reduce<Record<string, TPermission[]>>((acc, item) => {
    if (!acc[item.type]) acc[item.type] = [];
    acc[item.type].push(item);
    return acc;
  }, {});
};

const titleCaseFromSlug = (value: string) =>
  value
    .split('-')
    .filter(Boolean)
    .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
    .join(' ');

const EditPermission = () => {
  const { t } = useTranslation();
  const page = usePage();
  const roleId = Number(page.url.split('/')[3]);

  const { data: allPermissions, isLoading } = useApiSWR(
    '/admin/roles/permissions',
  );
  const {
    data: hasPermission,
    isLoading: permissionLoading,
    mutate,
  } = useApiSWR(`/admin/roles/permissions/for-role/${roleId}`);

  const assignedMap = useMemo(() => {
    const map: Record<number, boolean> = {};
    (hasPermission as THasPermission[] | undefined)?.forEach((p) => {
      map[p.id] = true;
    });
    return map;
  }, [hasPermission]);

  const [overrides, setOverrides] = useState<Record<number, boolean>>({});

  const isChecked = (id: number) =>
    overrides[id] !== undefined ? overrides[id] : !!assignedMap[id];

  const togglePermission = (permissionId: number, value: boolean) => {
    setOverrides((prev) => ({ ...prev, [permissionId]: value }));

    const action = value
      ? givePermission(permissionId, roleId)
      : revokePermission(permissionId, roleId);

    toast.promise(action, {
      loading: t('Updating...'),
      success: (res) => {
        const msg = res?.message || t('Updated');
        mutate();
        return msg;
      },
      error: (err) => err?.message || t('Failed to update'),
    });
  };

  const getGroupState = (permissions: TPermission[]) => {
    const total = permissions.length;
    const checkedCount = permissions.reduce(
      (sum, p) => sum + (isChecked(p.id) ? 1 : 0),
      0,
    );
    return {
      total,
      checkedCount,
      allChecked: total > 0 && checkedCount === total,
      someChecked: checkedCount > 0 && checkedCount < total,
    };
  };

  const toggleGroup = async (permissions: TPermission[], value: boolean) => {
    setOverrides((prev) => {
      const next = { ...prev };
      permissions.forEach((p) => {
        next[p.id] = value;
      });
      return next;
    });

    const toChange = permissions.filter((p) => isChecked(p.id) !== value);

    if (toChange.length === 0) {
      mutate();
      return;
    }

    const run = async () => {
      for (const p of toChange) {
        if (value) await givePermission(p.id, roleId);
        else await revokePermission(p.id, roleId);
      }
      await mutate();
      return t('Updated');
    };

    toast.promise(run(), {
      loading: t('Updating...'),
      success: () => t('Updated'),
      error: (err) => err?.message || t('Failed to update'),
    });
  };

  if (isLoading || permissionLoading) {
    return (
      <div className="flex h-96 w-full items-center justify-center gap-2">
        <LoaderIcon />
        {t('Loading...')}
      </div>
    );
  }

  const grouped = groupByType(allPermissions as TPermission[]);

  return (
    <>
      <PageHeading
        title={t('Edit Permission')}
        description={t(
          'Manage role permissions by toggling individual or group access.',
        )}
        backButton
      />

      <div className="overflow-hidden rounded-2xl shadow-box">
        <div className="flex h-14 items-center border-b border-black/5 bg-white px-4 md:px-6">
          <p className="text-lg font-medium">{t('Permissions')}</p>
        </div>

        {Object.entries(grouped).map(([type, permissions]) => {
          const sorted = [...permissions];
          const groupState = getGroupState(sorted);

          return (
            <div key={type}>
              {/* Group header */}
              <div className="flex items-center justify-between border-b border-black/5 bg-table-odd px-4 py-3 md:px-6">
                <p className="font-medium capitalize">{type}</p>
                <div className="flex items-center gap-2">
                  <Switch
                    checked={groupState.allChecked}
                    onCheckedChange={(val) => toggleGroup(sorted, val)}
                  />
                  <span className="text-sm">
                    {t('Select All')}
                    {groupState.someChecked ? (
                      <span className="ml-1.5 text-xs text-muted-foreground">
                        ({groupState.checkedCount}/{groupState.total})
                      </span>
                    ) : null}
                  </span>
                </div>
              </div>

              {/* Permission rows */}
              {sorted.map((permission, idx) => (
                <div
                  key={permission.id}
                  className={`flex items-center justify-between border-b border-black/5 px-4 py-3 md:px-6 md:pl-16 ${
                    idx % 2 === 0 ? 'bg-table-even' : 'bg-table-odd'
                  }`}
                >
                  <Label className="cursor-pointer text-sm">
                    {titleCaseFromSlug(permission.name)}
                  </Label>
                  <Switch
                    checked={isChecked(permission.id)}
                    onCheckedChange={(val) =>
                      togglePermission(permission.id, val)
                    }
                  />
                </div>
              ))}
            </div>
          );
        })}
      </div>
    </>
  );
};

EditPermission.title = 'Edit Permission';

export default EditPermission;
