import React, { useCallback, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import toast from 'react-hot-toast';
import { isAxiosError } from 'axios';
import { useQuery } from '@tanstack/react-query';
import { useLocale } from '@/app/providers/LocaleProvider';
import { AppLayout } from '@/shared/components/layout/AppLayout';
import {
  Button,
  Input,
  PanelLoadingState,
  PanelMessage,
  Select,
  Table,
  Th,
  Td,
  Tr,
  AdminPanel,
  TableWrap,
} from '@/shared/components/ui';
import { AdminPageShell } from '@/features/admin/components/AdminPageShell';
import {
  canSubmitDepartmentInviteRoleFields,
  DepartmentInviteRoleFields,
} from '@/features/admin/components/DepartmentInviteRoleFields';
import { inviteService, type UserInvite } from '@/features/admin/services/inviteService';
import { useAuthStore } from '@/features/auth/store/authStore';
import { usePermissions } from '@/features/auth/hooks/usePermissions';
import { PERMISSIONS } from '@/features/auth/constants/permissions';
import { listCompanies } from '@/features/admin/services/companyAdminService';
import { listDepartmentHeads, listDepartments } from '@/features/admin/services/departmentAdminService';
import type { Department } from '@/shared/types/api.types';
import { EmptyStateCard } from '@/features/onboarding/components/EmptyStateCard';
import {
  type InviteFieldErrors,
  resolveInviteEmailDomain,
  resolveInviteErrorMessage,
  validateInviteForm,
} from '@/features/admin/utils/inviteFormValidation';

const Form = styled.form`
  display: grid;
  gap: ${({ theme }) => theme.spacing[3]};
  margin-bottom: ${({ theme }) => theme.spacing[6]};
`;

function isManagedDepartment(department: Department): boolean {
  const record = department as Department & {
    is_department_head?: boolean;
    is_manager?: boolean;
  };
  return Boolean(record.is_department_head || record.is_manager);
}

const AdminInvitesPage: React.FC = () => {
  const { t } = useLocale();
  const user = useAuthStore((state) => state.user);
  const { isSuperAdmin, can } = usePermissions();
  const [invites, setInvites] = useState<UserInvite[]>([]);
  const [email, setEmail] = useState('');
  const [companyId, setCompanyId] = useState('');
  const [departmentId, setDepartmentId] = useState('');
  const [roleName, setRoleName] = useState('agent');
  const [isDepartmentHead, setIsDepartmentHead] = useState(false);
  const [transferAcknowledged, setTransferAcknowledged] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [isListLoading, setIsListLoading] = useState(true);
  const [listError, setListError] = useState<string | null>(null);
  const [fieldErrors, setFieldErrors] = useState<InviteFieldErrors>({});
  const [actionLoadingId, setActionLoadingId] = useState<string | null>(null);

  const managedDepartments = useMemo(
    () => (user?.departments ?? []).filter(isManagedDepartment),
    [user?.departments],
  );
  const isDepartmentHeadOnly =
    !isSuperAdmin &&
    !can(PERMISSIONS.COMPANY_USERS_MANAGE) &&
    can(PERMISSIONS.DEPARTMENT_USERS_MANAGE);
  const lockedDepartmentId = isDepartmentHeadOnly ? managedDepartments[0]?.id : undefined;

  const companiesQuery = useQuery({
    queryKey: ['admin', 'companies'],
    queryFn: () => listCompanies(),
    enabled: isSuperAdmin
  });

  const departmentsQuery = useQuery({
    queryKey: ['admin', 'departments', companyId || user?.company_id],
    queryFn: () =>
      listDepartments({
        company_id: isSuperAdmin ? companyId || undefined : user?.company_id
      }),
    enabled: Boolean(isSuperAdmin ? companyId : user?.company_id)
  });

  const resolvedCompanyId = isSuperAdmin ? companyId : user?.company_id;
  const resolvedDepartmentId = departmentId || lockedDepartmentId || '';
  const canSetOfficialHead = isSuperAdmin || can(PERMISSIONS.DEPARTMENT_HEADS_MANAGE);
  const showManagerOption =
    !isDepartmentHeadOnly && (isSuperAdmin || can(PERMISSIONS.COMPANY_USERS_MANAGE));

  const departmentHeadsQuery = useQuery({
    queryKey: ['admin', 'departments', resolvedDepartmentId, 'heads'],
    queryFn: () => listDepartmentHeads(resolvedDepartmentId),
    enabled: Boolean(resolvedDepartmentId) && canSetOfficialHead,
  });

  const allowedEmailDomain = resolveInviteEmailDomain(user?.company?.domain);
  const requiresTransferAck =
    isDepartmentHead && (departmentHeadsQuery.data?.length ?? 0) > 0;

  const validationMessages = useMemo(
    () => ({
      emailRequired: t('auth:invite.validation.emailRequired'),
      emailInvalid: t('auth:invite.validation.emailInvalid'),
      emailDomain: t('auth:invite.validation.emailDomain', { domain: allowedEmailDomain }),
      companyRequired: t('auth:invite.validation.companyRequired'),
      departmentRequired: t('auth:invite.validation.departmentRequired'),
      transferAckRequired: t('auth:invite.validation.transferAckRequired'),
    }),
    [allowedEmailDomain, t],
  );

  const apiErrorMessages = useMemo(
    () => ({
      forbidden: t('auth:invite.forbidden'),
      userExists: t('auth:invite.validation.userExists'),
      invalidDomain: t('auth:invite.validation.invalidDomain'),
      sendFailed: t('auth:invite.sendFailed'),
    }),
    [t],
  );

  const canSubmitInvite =
    Boolean(email.trim()) &&
    Boolean(resolvedCompanyId) &&
    Boolean(resolvedDepartmentId) &&
    canSubmitDepartmentInviteRoleFields(
      isDepartmentHead,
      departmentHeadsQuery.data?.length ?? 0,
      transferAcknowledged,
    );

  const loadInvites = useCallback(async () => {
    setIsListLoading(true);
    setListError(null);
    try {
      const data = await inviteService.list();
      setInvites(data);
    } catch (err) {
      setInvites([]);
      if (isAxiosError(err) && err.response?.status === 403) {
        setListError(t('admin:states.forbidden'));
      } else {
        setListError(t('auth:invite.loadError'));
      }
    } finally {
      setIsListLoading(false);
    }
  }, [t]);

  useEffect(() => {
    void loadInvites();
  }, [loadInvites]);

  useEffect(() => {
    if (user?.company_id && !companyId) {
      setCompanyId(user.company_id);
    }
    if (lockedDepartmentId) {
      setDepartmentId(lockedDepartmentId);
    }
  }, [user?.company_id, companyId, lockedDepartmentId]);

  useEffect(() => {
    setTransferAcknowledged(false);
  }, [resolvedDepartmentId, isDepartmentHead]);

  const handleSubmit = async (event: React.FormEvent) => {
    event.preventDefault();

    const validation = validateInviteForm({
      email,
      companyId: resolvedCompanyId,
      departmentId: resolvedDepartmentId,
      requireCompany: isSuperAdmin,
      requireDepartment: !isDepartmentHeadOnly,
      requiresTransferAck,
      transferAcknowledged,
      allowedDomain: allowedEmailDomain,
      messages: validationMessages,
    });

    if (!validation.valid) {
      setFieldErrors(validation.errors);
      const firstError =
        validation.errors.email ??
        validation.errors.company ??
        validation.errors.department ??
        validation.errors.transferAck;
      if (firstError) {
        toast.error(firstError);
      }
      return;
    }

    if (!resolvedCompanyId || !resolvedDepartmentId) {
      return;
    }

    setFieldErrors({});
    setIsLoading(true);
    try {
      await inviteService.create({
        email: validation.normalizedEmail,
        company_id: resolvedCompanyId,
        department_id: resolvedDepartmentId,
        role_name: roleName,
        is_department_head: canSetOfficialHead ? isDepartmentHead : false,
      });
      setEmail('');
      setIsDepartmentHead(false);
      setTransferAcknowledged(false);
      toast.success(
        t('auth:invite.sentSuccess', { email: validation.normalizedEmail }),
      );
      await loadInvites();
    } catch (error) {
      const resolved = resolveInviteErrorMessage(error, apiErrorMessages);
      if (resolved.field) {
        setFieldErrors((current) => ({ ...current, [resolved.field!]: resolved.message }));
      }
      toast.error(resolved.message);
    } finally {
      setIsLoading(false);
    }
  };

  const handleRevoke = async (invite: UserInvite) => {
    setActionLoadingId(invite.id);
    try {
      await inviteService.revoke(invite.id);
      toast.success(t('auth:invite.revokeSuccess', { email: invite.email }));
      await loadInvites();
    } catch (error) {
      const resolved = resolveInviteErrorMessage(error, {
        ...apiErrorMessages,
        sendFailed: t('auth:invite.revokeFailed'),
      });
      toast.error(resolved.message);
    } finally {
      setActionLoadingId(null);
    }
  };

  const handleResend = async (invite: UserInvite) => {
    setActionLoadingId(invite.id);
    try {
      await inviteService.resend(invite.id);
      toast.success(t('auth:invite.resendSuccess', { email: invite.email }));
      await loadInvites();
    } catch (error) {
      const resolved = resolveInviteErrorMessage(error, {
        ...apiErrorMessages,
        sendFailed: t('auth:invite.resendFailed'),
      });
      toast.error(resolved.message);
    } finally {
      setActionLoadingId(null);
    }
  };

  return (
    <AppLayout>
      <AdminPageShell
        title={t('auth:invite.adminTitle')}
        subtitle={t('auth:invite.adminSubtitle')}
        backLabel={t('settings:title')}
      >
        <AdminPanel>
          <Form onSubmit={handleSubmit}>
            <Input
              id="invite-email"
              type="email"
              label={t('auth:login.email')}
              value={email}
              onChange={(event) => {
                setEmail(event.target.value);
                if (fieldErrors.email) {
                  setFieldErrors((current) => ({ ...current, email: undefined }));
                }
              }}
              error={fieldErrors.email}
              hint={t('auth:invite.emailHint', { domain: allowedEmailDomain })}
              required
              fullWidth
            />
            {isSuperAdmin && (
              <Select
                label={t('admin:users.filters.company')}
                value={companyId}
                error={fieldErrors.company}
                onChange={(event) => {
                  setCompanyId(event.target.value);
                  setDepartmentId('');
                  if (fieldErrors.company) {
                    setFieldErrors((current) => ({ ...current, company: undefined }));
                  }
                }}
                options={[
                  { value: '', label: t('admin:users.selectCompany') },
                  ...(companiesQuery.data ?? []).map((company) => ({
                    value: company.id,
                    label: company.name
                  })),
                ]}
                fullWidth
                required
              />
            )}
            {isDepartmentHeadOnly ? (
              <Input
                label={t('admin:users.filters.department')}
                value={managedDepartments[0]?.name ?? ''}
                readOnly
                fullWidth
              />
            ) : (
              <Select
                label={t('admin:users.filters.department')}
                value={departmentId}
                error={fieldErrors.department}
                onChange={(event) => {
                  setDepartmentId(event.target.value);
                  if (fieldErrors.department) {
                    setFieldErrors((current) => ({ ...current, department: undefined }));
                  }
                }}
                options={[
                  { value: '', label: t('admin:users.selectDepartment') },
                  ...(departmentsQuery.data ?? []).map((department) => ({
                    value: department.id,
                    label: department.name
                  })),
                ]}
                fullWidth
                required
                disabled={!resolvedCompanyId}
              />
            )}
            <DepartmentInviteRoleFields
              roleName={roleName}
              isDepartmentHead={isDepartmentHead}
              onRoleNameChange={setRoleName}
              onDepartmentHeadChange={(value) => {
                setIsDepartmentHead(value);
                if (!value) {
                  setTransferAcknowledged(false);
                }
              }}
              canSetOfficialHead={canSetOfficialHead}
              showManagerOption={showManagerOption}
              departmentId={resolvedDepartmentId || undefined}
              transferAcknowledged={transferAcknowledged}
              onTransferAcknowledgedChange={(value) => {
                setTransferAcknowledged(value);
                if (fieldErrors.transferAck) {
                  setFieldErrors((current) => ({ ...current, transferAck: undefined }));
                }
              }}
            />
            {fieldErrors.transferAck ? (
              <PanelMessage $variant="error">{fieldErrors.transferAck}</PanelMessage>
            ) : null}
            <Button type="submit" variant="primary" loading={isLoading} disabled={!canSubmitInvite}>
              {t('auth:invite.send')}
            </Button>
          </Form>

          {isListLoading ? (
            <PanelLoadingState />
          ) : listError ? (
            <PanelMessage $variant="error">{t('admin:states.error')}</PanelMessage>
          ) : invites.length === 0 ? (
            <EmptyStateCard
              icon="✉️"
              title={t('onboarding:emptyStates.invites.title')}
              description={t('onboarding:emptyStates.invites.description')}
              actionLabel={t('onboarding:emptyStates.invites.action')}
              onAction={() => document.getElementById('invite-email')?.focus()}
            />
          ) : (
            <TableWrap>
              <Table>
                <thead>
                  <tr>
                    <Th>{t('auth:login.email')}</Th>
                    <Th>{t('admin:users.filters.department')}</Th>
                    <Th>{t('auth:invite.status')}</Th>
                    <Th />
                  </tr>
                </thead>
                <tbody>
                  {invites.map((invite) => (
                    <Tr key={invite.id}>
                      <Td>{invite.email}</Td>
                      <Td>{invite.department_id ?? '—'}</Td>
                      <Td>{invite.status}</Td>
                      <Td>
                        {invite.status === 'pending' && (
                          <>
                            <Button
                              type="button"
                              variant="ghost"
                              size="sm"
                              loading={actionLoadingId === invite.id}
                              disabled={actionLoadingId !== null && actionLoadingId !== invite.id}
                              onClick={() => void handleResend(invite)}
                            >
                              {t('auth:invite.resend')}
                            </Button>
                            <Button
                              type="button"
                              variant="ghost"
                              size="sm"
                              loading={actionLoadingId === invite.id}
                              disabled={actionLoadingId !== null && actionLoadingId !== invite.id}
                              onClick={() => void handleRevoke(invite)}
                            >
                              {t('auth:invite.revoke')}
                            </Button>
                          </>
                        )}
                      </Td>
                    </Tr>))}
                </tbody>
              </Table>
            </TableWrap>
          )}
        </AdminPanel>
      </AdminPageShell>
    </AppLayout>
  );
};

export default AdminInvitesPage;
