import {
  DeleteOutlined,
  EditOutlined,
  PlusOutlined,
  ReloadOutlined
} from '@ant-design/icons';
import {
  Alert,
  App as AntApp,
  Button,
  Card,
  Checkbox,
  Descriptions,
  Drawer,
  Input,
  List,
  Select,
  Skeleton,
  Space,
  Table,
  Tag,
  Typography
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useSearchParams } from 'react-router-dom';

import { EmptyState } from '../../components/common/EmptyState';
import { SectionCard } from '../../components/common/SectionCard';
import { MailboxPermissionTags } from '../../components/mailbox/MailboxPermissionTags';
import { useI18n } from '../../frontend/i18n/react';
import { api } from '../../frontend/services/api';
import type {
  AdminMailboxAccessEntry,
  AdminUser,
  MailboxPermissions
} from '../../frontend/types';
import { useMediaQuery } from '../../frontend/use-media-query';

type DraftGrant = { userId: number } & MailboxPermissions;

export function AdminMailboxAccess({ users }: { users: AdminUser[] }) {
  const { message } = AntApp.useApp();
  const { t } = useI18n();
  const isTableView = useMediaQuery('(min-width: 768px)');
  const [searchParams, setSearchParams] = useSearchParams();
  const [entries, setEntries] = useState<AdminMailboxAccessEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState('');
  const [query, setQuery] = useState('');
  const [draftGrants, setDraftGrants] = useState<DraftGrant[]>([]);
  const [actionKey, setActionKey] = useState('');
  const drawerTitleRef = useRef<HTMLSpanElement>(null);
  const mailboxId = positiveInteger(searchParams.get('mailboxId'));
  const selected = mailboxId ? entries.find((entry) => entry.mailbox.id === mailboxId) || null : null;

  const loadEntries = useCallback(async () => {
    setLoading(true);
    setLoadError('');
    try {
      const result = await api.adminMailboxAccess();
      setEntries(result.mailboxes || []);
    } catch (error) {
      setLoadError(error instanceof Error ? error.message : t('common.error'));
    } finally {
      setLoading(false);
    }
  }, [t]);

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

  useEffect(() => {
    if (!selected) {
      setDraftGrants([]);
      return;
    }
    setDraftGrants(selected.grants.map((grant) => ({
      userId: grant.user.id,
      ...normalizePermissions(grant.permissions)
    })));
  }, [selected]);

  const visibleEntries = useMemo(() => {
    const needle = query.trim().toLowerCase();
    if (!needle) return entries;
    return entries.filter((entry) => [
      entry.mailbox.address,
      entry.mailbox.displayName,
      entry.owner.username,
      entry.owner.email
    ].some((value) => String(value || '').toLowerCase().includes(needle)));
  }, [entries, query]);

  function openDrawer(entry: AdminMailboxAccessEntry) {
    const next = new URLSearchParams(searchParams);
    next.set('mailboxId', String(entry.mailbox.id));
    setSearchParams(next);
  }

  function closeDrawer() {
    const closingId = mailboxId;
    const next = new URLSearchParams(searchParams);
    next.delete('mailboxId');
    setSearchParams(next);
    if (closingId) {
      window.requestAnimationFrame(() => {
        document.querySelector<HTMLElement>(`[data-mailbox-access-trigger="${closingId}"]`)?.focus();
      });
    }
  }

  function addGrant() {
    const used = new Set(draftGrants.map((grant) => grant.userId));
    const ownerId = selected ? ownerIdForEntry(selected) : 0;
    const candidate = users.find((user) => user.id !== ownerId && user.status !== 'disabled' && !used.has(user.id));
    if (!candidate) return;
    setDraftGrants((current) => [...current, { userId: candidate.id, view: true, receive: false, send: false }]);
  }

  function updateGrant(index: number, patch: Partial<DraftGrant>) {
    setDraftGrants((current) => current.map((grant, currentIndex) => {
      if (currentIndex !== index) return grant;
      const next = { ...grant, ...patch };
      if (next.receive || next.send) next.view = true;
      return next;
    }));
  }

  async function saveGrants() {
    if (!selected) return;
    const duplicate = draftGrants.find((grant, index) => draftGrants.some((other, otherIndex) => (
      otherIndex !== index && other.userId === grant.userId
    )));
    if (duplicate) {
      message.error(t('adminMailboxAccess.duplicateUser'));
      return;
    }
    if (draftGrants.some((grant) => !grant.view && !grant.receive && !grant.send)) {
      message.error(t('adminMailboxAccess.permissionRequired'));
      return;
    }
    const key = `mailbox-access:${selected.mailbox.id}`;
    setActionKey(key);
    try {
      const result = await api.saveAdminMailboxAccess(selected.mailbox.id, draftGrants.map((grant) => ({
        userId: grant.userId,
        ...normalizePermissions(grant)
      })));
      setEntries((current) => current.map((entry) => (
        entry.mailbox.id === result.mailbox.mailbox.id ? result.mailbox : entry
      )));
      message.success(t('adminMailboxAccess.saved'));
    } catch (error) {
      message.error(error instanceof Error ? error.message : t('common.error'));
    } finally {
      setActionKey('');
    }
  }

  function availableUsers(index: number) {
    const usedByOtherRows = new Set(draftGrants
      .filter((_grant, currentIndex) => currentIndex !== index)
      .map((grant) => grant.userId));
    const ownerId = selected ? ownerIdForEntry(selected) : 0;
    return users
      .filter((user) => user.id !== ownerId && !usedByOtherRows.has(user.id))
      .map((user) => ({
        value: user.id,
        label: `${user.username} · ${user.email}${user.status === 'disabled' ? ` · ${t('adminMailboxAccess.disabledUser')}` : ''}`,
        disabled: user.status === 'disabled'
      }));
  }

  const columns: ColumnsType<AdminMailboxAccessEntry> = [
    {
      title: t('inbox.mailboxAddress'),
      render: (_, entry) => (
        <Space direction="vertical" size={0}>
          <Typography.Text strong>{entry.mailbox.address}</Typography.Text>
          {entry.mailbox.displayName ? <Typography.Text type="secondary">{entry.mailbox.displayName}</Typography.Text> : null}
        </Space>
      )
    },
    {
      title: t('adminMailboxAccess.owner'),
      width: 220,
      render: (_, entry) => (
        <Space direction="vertical" size={0}>
          <Typography.Text>{entry.owner.username}</Typography.Text>
          <Typography.Text type="secondary">{entry.owner.email}</Typography.Text>
        </Space>
      )
    },
    {
      title: t('adminMailboxAccess.assignedUsers'),
      width: 170,
      render: (_, entry) => <Tag>{entry.grants.length}</Tag>
    },
    {
      title: t('common.actions'),
      align: 'right',
      width: 150,
      render: (_, entry) => (
        <Button
          data-mailbox-access-trigger={entry.mailbox.id}
          aria-label={`${t('adminMailboxAccess.configure')} · ${entry.mailbox.address}`}
          icon={<EditOutlined />}
          style={{ minHeight: 44 }}
          onClick={() => openDrawer(entry)}
        >
          {t('adminMailboxAccess.configure')}
        </Button>
      )
    }
  ];

  return (
    <Space direction="vertical" size={16} className="full-width">
      <Space wrap className="admin-mailbox-access-toolbar">
        <Input.Search
          allowClear
          aria-label={t('adminMailboxAccess.search')}
          placeholder={t('adminMailboxAccess.search')}
          value={query}
          onChange={(event) => setQuery(event.target.value)}
        />
        <Button icon={<ReloadOutlined />} loading={loading} style={{ minHeight: 44 }} onClick={() => void loadEntries()}>
          {t('common.refresh')}
        </Button>
      </Space>
      {loadError ? <Alert type="error" showIcon message={loadError} action={<Button onClick={() => void loadEntries()}>{t('common.refresh')}</Button>} /> : null}
      <SectionCard title={t('adminMailboxAccess.title')} extra={<Tag>{entries.length}</Tag>}>
        {loading && !entries.length ? <Skeleton active paragraph={{ rows: 8 }} /> : visibleEntries.length ? (
          isTableView ? (
            <Table rowKey={(entry) => entry.mailbox.id} columns={columns} dataSource={visibleEntries} scroll={{ x: 760 }} />
          ) : (
            <List
              dataSource={visibleEntries}
              renderItem={(entry) => (
                <List.Item>
                  <Card size="small" className="full-width admin-mailbox-access-card" title={entry.mailbox.address}>
                    <Space direction="vertical" size={12} className="full-width">
                      <Typography.Text type="secondary">{t('adminMailboxAccess.owner')} · {entry.owner.username}</Typography.Text>
                      <Tag>{t('adminMailboxAccess.assignedUsers')} {entry.grants.length}</Tag>
                      <Button
                        block
                        data-mailbox-access-trigger={entry.mailbox.id}
                        aria-label={`${t('adminMailboxAccess.configure')} · ${entry.mailbox.address}`}
                        icon={<EditOutlined />}
                        style={{ minHeight: 44 }}
                        onClick={() => openDrawer(entry)}
                      >
                        {t('adminMailboxAccess.configure')}
                      </Button>
                    </Space>
                  </Card>
                </List.Item>
              )}
            />
          )
        ) : <EmptyState description={query ? t('adminMailboxAccess.noSearchResult') : t('adminMailboxAccess.empty')} />}
      </SectionCard>

      <Drawer
        title={<span ref={drawerTitleRef} tabIndex={-1}>{selected?.mailbox.address || t('adminMailboxAccess.drawerTitle')}</span>}
        width={isTableView ? 720 : '100%'}
        open={Boolean(mailboxId)}
        onClose={closeDrawer}
        destroyOnHidden
        afterOpenChange={(open) => {
          if (open) window.requestAnimationFrame(() => drawerTitleRef.current?.focus({ preventScroll: true }));
        }}
        footer={selected ? (
          <Space className="admin-mailbox-access-footer">
            <Button style={{ minHeight: 44 }} onClick={closeDrawer}>{t('common.cancel')}</Button>
            <Button
              type="primary"
              style={{ minHeight: 44 }}
              loading={actionKey === `mailbox-access:${selected.mailbox.id}`}
              onClick={() => void saveGrants()}
            >
              {t('common.save')}
            </Button>
          </Space>
        ) : null}
      >
        {loading && !selected ? <Skeleton active paragraph={{ rows: 8 }} /> : selected ? (
          <Space direction="vertical" size={20} className="full-width">
            <Descriptions bordered size="small" column={1}>
              <Descriptions.Item label={t('inbox.mailboxAddress')}>{selected.mailbox.address}</Descriptions.Item>
              <Descriptions.Item label={t('adminMailboxAccess.owner')}>
                {selected.owner.username} · {selected.owner.email}
              </Descriptions.Item>
              <Descriptions.Item label={t('adminMailboxAccess.ownerPermissions')}>
                <MailboxPermissionTags permissions={{ view: true, receive: true, send: true }} />
              </Descriptions.Item>
            </Descriptions>
            <Alert type="info" showIcon message={t('adminMailboxAccess.permissionHint')} />
            <Space direction="vertical" size={12} className="full-width">
              {draftGrants.map((grant, index) => {
                const selectedUser = users.find((user) => user.id === grant.userId);
                return (
                  <Card
                    key={`${grant.userId}:${index}`}
                    size="small"
                    title={selectedUser?.username || t('common.user')}
                    extra={(
                      <Button
                        danger
                        type="text"
                        icon={<DeleteOutlined />}
                        aria-label={`${t('adminMailboxAccess.remove')} ${selectedUser?.username || grant.userId}`}
                        style={{ minHeight: 44, minWidth: 44 }}
                        onClick={() => setDraftGrants((current) => current.filter((_item, currentIndex) => currentIndex !== index))}
                      />
                    )}
                  >
                    <Space direction="vertical" size={12} className="full-width">
                      <Select
                        aria-label={`${t('adminMailboxAccess.user')} ${index + 1}`}
                        showSearch
                        optionFilterProp="label"
                        value={grant.userId}
                        options={availableUsers(index)}
                        className="full-width"
                        onChange={(userId) => updateGrant(index, { userId })}
                      />
                      <div role="group" aria-label={`${t('adminMailboxAccess.permissions')} · ${selectedUser?.username || grant.userId}`} className="admin-mailbox-permissions">
                        <Checkbox
                          checked={grant.view}
                          disabled={grant.receive || grant.send}
                          onChange={(event) => updateGrant(index, { view: event.target.checked })}
                        >
                          {t('mailboxPermission.view')}
                        </Checkbox>
                        <Checkbox checked={grant.receive} onChange={(event) => updateGrant(index, { receive: event.target.checked })}>
                          {t('mailboxPermission.receive')}
                        </Checkbox>
                        <Checkbox checked={grant.send} onChange={(event) => updateGrant(index, { send: event.target.checked })}>
                          {t('mailboxPermission.send')}
                        </Checkbox>
                      </div>
                    </Space>
                  </Card>
                );
              })}
              {!draftGrants.length ? <EmptyState description={t('adminMailboxAccess.noAssignments')} /> : null}
              <Button
                type="dashed"
                block
                icon={<PlusOutlined />}
                style={{ minHeight: 44 }}
                disabled={!users.some((user) => user.status !== 'disabled' && user.id !== ownerIdForEntry(selected) && !draftGrants.some((grant) => grant.userId === user.id))}
                onClick={addGrant}
              >
                {t('adminMailboxAccess.addUser')}
              </Button>
            </Space>
          </Space>
        ) : (
          <Alert type="error" showIcon message={loadError || t('adminMailboxAccess.notFound')} action={<Button onClick={closeDrawer}>{t('common.confirm')}</Button>} />
        )}
      </Drawer>
    </Space>
  );
}

function ownerIdForEntry(entry: AdminMailboxAccessEntry) {
  return entry.mailbox.ownerUserId || entry.mailbox.userId || entry.owner.id;
}

function normalizePermissions(permissions: Partial<MailboxPermissions>) {
  const receive = Boolean(permissions.receive);
  const send = Boolean(permissions.send);
  return {
    view: Boolean(permissions.view) || receive || send,
    receive,
    send
  };
}

function positiveInteger(value: string | null) {
  const number = Number(value);
  return Number.isInteger(number) && number > 0 ? number : null;
}
