'use client';

import { useState, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiClient } from '@/infrastructure/api/api-client';
import { queryKeys } from '@/infrastructure/api/query-keys';
import { cn } from '@/lib/utils';

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

interface Permission {
  id: string;
  key: string;
  resource: string;
  action: string;
  description: string;
}

interface Role {
  id: string;
  name: string;
  description: string;
  permissionCount: number;
  userCount: number;
  isSystem: boolean;
  createdAt: string;
}

type RolesResponse = Role[];

type RolePermissionsResponse = Permission[];

type PermissionsListResponse = Permission[];

interface RoleFormData {
  name: string;
  description: string;
}

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const EMPTY_FORM: RoleFormData = {
  name: '',
  description: '',
};

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function formatDate(dateStr: string): string {
  try {
    return new Date(dateStr).toLocaleDateString('en-US', {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
    });
  } catch {
    return dateStr;
  }
}

// ---------------------------------------------------------------------------
// System badge
// ---------------------------------------------------------------------------

function SystemBadge({ isSystem }: { isSystem: boolean }) {
  const { t } = useTranslation('security');
  if (!isSystem) return null;
  return (
    <span
      className={cn(
        'inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium',
        'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',
      )}
    >
      {t('roles.builtIn')}
    </span>
  );
}

// ---------------------------------------------------------------------------
// Add / Edit Role dialog
// ---------------------------------------------------------------------------

function RoleDialog({
  open,
  title,
  form,
  errors,
  saving,
  onClose,
  onChange,
  onSubmit,
}: {
  open: boolean;
  title: string;
  form: RoleFormData;
  errors: Partial<Record<keyof RoleFormData, string>>;
  saving: boolean;
  onClose: () => void;
  onChange: (field: keyof RoleFormData, value: string) => void;
  onSubmit: () => void;
}) {
  const { t } = useTranslation('security');
  const { t: tc } = useTranslation('common');
  if (!open) return null;

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center">
      <div className="absolute inset-0 bg-black/50" onClick={onClose} />

      <div className="relative z-10 w-full max-w-lg bg-card border rounded-lg shadow-lg p-6 mx-4">
        <h2 className="text-lg font-semibold mb-4">{title}</h2>

        <div className="space-y-4">
          {/* name */}
          <div>
            <label className="block text-sm font-medium mb-1">
              {t('roles.form.name')} <span className="text-destructive">*</span>
            </label>
            <input
              type="text"
              value={form.name}
              onChange={(e) => onChange('name', e.target.value)}
              className={cn(
                'w-full px-3 py-2 rounded-md border bg-background text-sm',
                errors.name ? 'border-destructive' : 'border-input',
              )}
              placeholder="e.g. Operator"
            />
            {errors.name && (
              <p className="text-xs text-destructive mt-1">{errors.name}</p>
            )}
          </div>

          {/* description */}
          <div>
            <label className="block text-sm font-medium mb-1">{t('roles.form.description')}</label>
            <textarea
              value={form.description}
              onChange={(e) => onChange('description', e.target.value)}
              rows={3}
              className="w-full px-3 py-2 rounded-md border border-input bg-background text-sm resize-none"
              placeholder="Describe the role's purpose..."
            />
          </div>
        </div>

        <div className="flex justify-end gap-3 mt-6 pt-4 border-t">
          <button
            type="button"
            onClick={onClose}
            className="px-4 py-2 text-sm rounded-md border border-input hover:bg-accent"
            disabled={saving}
          >
            {tc('cancel')}
          </button>
          <button
            type="button"
            onClick={onSubmit}
            disabled={saving}
            className="px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
          >
            {saving ? tc('saving') : tc('save')}
          </button>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Delete role confirmation dialog
// ---------------------------------------------------------------------------

function DeleteRoleDialog({
  open,
  roleName,
  userCount,
  deleting,
  onClose,
  onConfirm,
}: {
  open: boolean;
  roleName: string;
  userCount: number;
  deleting: boolean;
  onClose: () => void;
  onConfirm: () => void;
}) {
  const { t } = useTranslation('security');
  const { t: tc } = useTranslation('common');
  if (!open) return null;

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center">
      <div className="absolute inset-0 bg-black/50" onClick={onClose} />
      <div className="relative z-10 w-full max-w-sm bg-card border rounded-lg shadow-lg p-6 mx-4">
        <h2 className="text-lg font-semibold mb-2">{t('roles.deleteRole')}</h2>
        <p className="text-sm text-muted-foreground mb-4">
          {tc('confirmDelete')} <strong>{roleName}</strong>
        </p>

        {userCount > 0 && (
          <div className="p-3 mb-4 rounded-md border border-destructive/50 bg-destructive/10 text-sm text-destructive">
            <strong>{tc('warning')}:</strong> This role is currently assigned to{' '}
            <strong>{userCount}</strong> user{userCount !== 1 ? 's' : ''}.
            Those users will lose the permissions granted by this role.
          </div>
        )}

        <div className="flex justify-end gap-3">
          <button
            onClick={onClose}
            className="px-4 py-2 text-sm rounded-md border border-input hover:bg-accent"
            disabled={deleting}
          >
            {tc('cancel')}
          </button>
          <button
            onClick={onConfirm}
            disabled={deleting}
            className="px-4 py-2 text-sm rounded-md bg-destructive text-destructive-foreground hover:bg-destructive/90 disabled:opacity-50"
          >
            {deleting ? tc('deleting') : tc('delete')}
          </button>
        </div>
      </div>
    </div>
  );
}

// ---------------------------------------------------------------------------
// Permissions panel (expandable per role)
// ---------------------------------------------------------------------------

function PermissionsPanel({
  roleId,
  allPermissions,
  rolePermissions,
  saving,
  onToggle,
}: {
  roleId: string;
  allPermissions: Permission[];
  rolePermissions: Permission[];
  saving: boolean;
  onToggle: (roleId: string, permissionId: string, checked: boolean) => void;
}) {
  const { t } = useTranslation('security');
  const assignedIds = useMemo(
    () => new Set(rolePermissions.map((p) => p.id)),
    [rolePermissions],
  );

  const grouped = useMemo(() => {
    const groups: Record<string, Permission[]> = {};
    for (const perm of allPermissions) {
      const resource = perm.resource || 'general';
      if (!groups[resource]) groups[resource] = [];
      groups[resource].push(perm);
    }
    return groups;
  }, [allPermissions]);

  return (
    <div className="px-4 py-4 bg-muted/20">
      <h3 className="text-sm font-semibold mb-3">{t('roles.assignedPermissions')}</h3>
      {Object.keys(grouped).length === 0 ? (
        <p className="text-sm text-muted-foreground">No permissions available.</p>
      ) : (
        <div className="space-y-4">
          {Object.entries(grouped).map(([resource, perms]) => (
            <div key={resource}>
              <p className="text-xs font-semibold text-muted-foreground uppercase tracking-wide mb-2">
                {resource}
              </p>
              <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
                {perms.map((perm) => {
                  const checked = assignedIds.has(perm.id);
                  return (
                    <label
                      key={perm.id}
                      className="flex items-start gap-2 p-2 rounded-md hover:bg-muted/40 cursor-pointer"
                    >
                      <input
                        type="checkbox"
                        checked={checked}
                        onChange={() => onToggle(roleId, perm.id, !checked)}
                        disabled={saving}
                        className="h-4 w-4 mt-0.5 rounded border-input text-primary focus:ring-primary cursor-pointer"
                      />
                      <div className="min-w-0">
                        <p className="text-sm font-medium">{perm.key}</p>
                        {perm.description && (
                          <p className="text-xs text-muted-foreground truncate">
                            {perm.description}
                          </p>
                        )}
                      </div>
                    </label>
                  );
                })}
              </div>
            </div>
          ))}
        </div>
      )}
      {saving && (
        <p className="text-xs text-muted-foreground mt-2">{t('roles.savingPermissions')}</p>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// Main page component
// ---------------------------------------------------------------------------

export default function RolesPage() {
  const { t } = useTranslation('security');
  const { t: tc } = useTranslation('common');
  const queryClient = useQueryClient();

  // State ----------------------------------------------------------------
  const [dialogOpen, setDialogOpen] = useState(false);
  const [editingRole, setEditingRole] = useState<Role | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<Role | null>(null);
  const [expandedRoleId, setExpandedRoleId] = useState<string | null>(null);
  const [form, setForm] = useState<RoleFormData>({ ...EMPTY_FORM });
  const [errors, setErrors] = useState<Partial<Record<keyof RoleFormData, string>>>({});

  // Queries --------------------------------------------------------------
  const { data: rolesData, isLoading, error } = useQuery({
    queryKey: queryKeys.roles.list(),
    queryFn: () => apiClient<RolesResponse>('/api/v1/auth/roles'),
  });

  const roles = Array.isArray(rolesData) ? rolesData : [];

  // Fetch all permissions (for checkbox lists)
  const { data: allPermsData } = useQuery({
    queryKey: queryKeys.permissions.list(),
    queryFn: () => apiClient<PermissionsListResponse>('/api/v1/auth/permissions'),
  });

  const allPermissions = Array.isArray(allPermsData) ? allPermsData : [];

  // Fetch permissions for expanded role
  const { data: rolePermsData, isLoading: rolePermsLoading } = useQuery({
    queryKey: queryKeys.roles.permissions(expandedRoleId ?? ''),
    queryFn: () =>
      apiClient<RolePermissionsResponse>(
        `/api/v1/auth/roles/${expandedRoleId}/permissions`,
      ),
    enabled: !!expandedRoleId,
  });

  const rolePermissions = Array.isArray(rolePermsData) ? rolePermsData : [];

  // Mutations ------------------------------------------------------------
  const createMutation = useMutation({
    mutationFn: (body: Record<string, unknown>) =>
      apiClient<Role>('/api/v1/auth/roles', { method: 'POST', body }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.roles.all });
      closeDialog();
    },
  });

  const updateMutation = useMutation({
    mutationFn: ({ id, body }: { id: string; body: Record<string, unknown> }) =>
      apiClient<Role>(`/api/v1/auth/roles/${id}`, { method: 'PUT', body }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.roles.all });
      closeDialog();
    },
  });

  const deleteMutation = useMutation({
    mutationFn: (id: string) =>
      apiClient<void>(`/api/v1/auth/roles/${id}`, { method: 'DELETE' }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.roles.all });
      setDeleteTarget(null);
    },
  });

  const togglePermissionMutation = useMutation({
    mutationFn: ({
      roleId,
      permissionId,
      assign,
    }: {
      roleId: string;
      permissionId: string;
      assign: boolean;
    }) =>
      apiClient<void>(`/api/v1/auth/roles/${roleId}/permissions`, {
        method: assign ? 'POST' : 'DELETE',
        body: { permissionId },
      }),
    onSuccess: (_data, variables) => {
      queryClient.invalidateQueries({
        queryKey: queryKeys.roles.permissions(variables.roleId),
      });
      queryClient.invalidateQueries({ queryKey: queryKeys.roles.all });
    },
  });

  // Helpers --------------------------------------------------------------
  const validate = useCallback((): boolean => {
    const next: Partial<Record<keyof RoleFormData, string>> = {};
    if (!form.name.trim()) next.name = 'Name is required';
    setErrors(next);
    return Object.keys(next).length === 0;
  }, [form]);

  const closeDialog = useCallback(() => {
    setDialogOpen(false);
    setEditingRole(null);
    setForm({ ...EMPTY_FORM });
    setErrors({});
  }, []);

  const openAdd = useCallback(() => {
    setEditingRole(null);
    setForm({ ...EMPTY_FORM });
    setErrors({});
    setDialogOpen(true);
  }, []);

  const openEdit = useCallback((role: Role) => {
    setEditingRole(role);
    setForm({
      name: role.name,
      description: role.description ?? '',
    });
    setErrors({});
    setDialogOpen(true);
  }, []);

  const handleChange = useCallback(
    (field: keyof RoleFormData, value: string) => {
      setForm((prev) => ({ ...prev, [field]: value }));
      setErrors((prev) => {
        const next = { ...prev };
        delete next[field];
        return next;
      });
    },
    [],
  );

  const handleSubmit = useCallback(() => {
    if (!validate()) return;
    const body: Record<string, unknown> = {
      name: form.name.trim(),
      description: form.description.trim(),
    };

    if (editingRole) {
      updateMutation.mutate({ id: editingRole.id, body });
    } else {
      createMutation.mutate(body);
    }
  }, [form, editingRole, validate, createMutation, updateMutation]);

  const handleTogglePermission = useCallback(
    (roleId: string, permissionId: string, assign: boolean) => {
      togglePermissionMutation.mutate({ roleId, permissionId, assign });
    },
    [togglePermissionMutation],
  );

  const toggleExpand = useCallback(
    (roleId: string) => {
      setExpandedRoleId((prev) => (prev === roleId ? null : roleId));
    },
    [],
  );

  const isSaving = createMutation.isPending || updateMutation.isPending;

  // Render ---------------------------------------------------------------
  return (
    <div>
      {/* Header */}
      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-6">
        <div>
          <h1 className="text-2xl font-bold">{t('roles.title')}</h1>
          <p className="text-sm text-muted-foreground mt-1">
            {t('roles.subtitle')}
          </p>
        </div>
        <button
          onClick={openAdd}
          className="px-4 py-2 text-sm rounded-md bg-primary text-primary-foreground hover:bg-primary/90 whitespace-nowrap"
        >
          {t('roles.addRole')}
        </button>
      </div>

      {/* Error state */}
      {error && (
        <div className="p-4 mb-4 rounded-md border border-destructive/50 bg-destructive/10 text-destructive text-sm">
          {t('roles.loadError')} {(error as Error).message}
        </div>
      )}

      {/* Loading state */}
      {isLoading && (
        <div className="text-sm text-muted-foreground py-12 text-center">
          {t('roles.loading')}
        </div>
      )}

      {/* Data table */}
      {!isLoading && !error && (
        <div className="border rounded-lg overflow-hidden">
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b bg-muted/50">
                  <th className="text-left px-4 py-3 font-medium">{t('roles.table.name')}</th>
                  <th className="text-left px-4 py-3 font-medium">{t('roles.table.description')}</th>
                  <th className="text-left px-4 py-3 font-medium">{t('roles.table.type')}</th>
                  <th className="text-right px-4 py-3 font-medium">{t('roles.table.permissions')}</th>
                  <th className="text-right px-4 py-3 font-medium">{t('roles.table.users')}</th>
                  <th className="text-left px-4 py-3 font-medium">{t('roles.table.created')}</th>
                  <th className="text-right px-4 py-3 font-medium">{t('roles.table.actions')}</th>
                </tr>
              </thead>
              <tbody>
                {roles.length === 0 ? (
                  <tr>
                    <td
                      colSpan={7}
                      className="text-center text-muted-foreground py-12"
                    >
                      {t('roles.empty')}
                    </td>
                  </tr>
                ) : (
                  roles.map((role) => (
                    <>
                      <tr
                        key={role.id}
                        className="border-b last:border-b-0 hover:bg-muted/30 transition-colors"
                      >
                        <td className="px-4 py-3">
                          <span className="font-medium">{role.name}</span>
                        </td>
                        <td className="px-4 py-3 text-muted-foreground max-w-xs truncate">
                          {role.description || '--'}
                        </td>
                        <td className="px-4 py-3">
                          <SystemBadge isSystem={role.isSystem} />
                          {!role.isSystem && (
                            <span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-800 dark:bg-gray-800/40 dark:text-gray-300">
                              {t('roles.custom')}
                            </span>
                          )}
                        </td>
                        <td className="px-4 py-3 text-right tabular-nums">
                          {role.permissionCount}
                        </td>
                        <td className="px-4 py-3 text-right tabular-nums">
                          {role.userCount}
                        </td>
                        <td className="px-4 py-3 text-muted-foreground">
                          {formatDate(role.createdAt)}
                        </td>
                        <td className="px-4 py-3 text-right">
                          <div className="flex items-center justify-end gap-2">
                            <button
                              onClick={() => toggleExpand(role.id)}
                              className="px-3 py-1 text-xs rounded-md border border-input hover:bg-accent transition-colors"
                            >
                              {expandedRoleId === role.id ? t('roles.hidePerms') : t('roles.showPerms')}
                            </button>
                            <button
                              onClick={() => openEdit(role)}
                              className="px-3 py-1 text-xs rounded-md border border-input hover:bg-accent transition-colors"
                            >
                              {tc('edit')}
                            </button>
                            {!role.isSystem && (
                              <button
                                onClick={() => setDeleteTarget(role)}
                                className="px-3 py-1 text-xs rounded-md border border-destructive/50 text-destructive hover:bg-destructive/10 transition-colors"
                              >
                                {tc('delete')}
                              </button>
                            )}
                          </div>
                        </td>
                      </tr>

                      {/* Expanded permissions row */}
                      {expandedRoleId === role.id && (
                        <tr key={`${role.id}-perms`}>
                          <td colSpan={7}>
                            {rolePermsLoading ? (
                              <div className="px-4 py-6 text-sm text-muted-foreground text-center">
                                {tc('loading')}
                              </div>
                            ) : (
                              <PermissionsPanel
                                roleId={role.id}
                                allPermissions={allPermissions}
                                rolePermissions={rolePermissions}
                                saving={togglePermissionMutation.isPending}
                                onToggle={handleTogglePermission}
                              />
                            )}
                          </td>
                        </tr>
                      )}
                    </>
                  ))
                )}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* Add / Edit role dialog */}
      <RoleDialog
        open={dialogOpen}
        title={editingRole ? t('roles.editRole') : t('roles.addRole')}
        form={form}
        errors={errors}
        saving={isSaving}
        onClose={closeDialog}
        onChange={handleChange}
        onSubmit={handleSubmit}
      />

      {/* Delete confirmation dialog */}
      <DeleteRoleDialog
        open={!!deleteTarget}
        roleName={deleteTarget?.name ?? ''}
        userCount={deleteTarget?.userCount ?? 0}
        deleting={deleteMutation.isPending}
        onClose={() => setDeleteTarget(null)}
        onConfirm={() => {
          if (deleteTarget) deleteMutation.mutate(deleteTarget.id);
        }}
      />
    </div>
  );
}
