import {
  CopyOutlined,
  DeleteOutlined,
  EditOutlined,
  PlusOutlined,
  ReloadOutlined
} from '@ant-design/icons';
import {
  Alert,
  App as AntApp,
  Button,
  Descriptions,
  Drawer,
  Form,
  Input,
  InputNumber,
  Popconfirm,
  Skeleton,
  Space,
  Switch,
  Table,
  Tabs,
  Typography
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';

import { EmptyState } from '../components/common/EmptyState';
import { PageHeader } from '../components/common/PageHeader';
import { SectionCard } from '../components/common/SectionCard';
import { StatusPill } from '../components/common/StatusPill';
import { useAppContext } from '../frontend/app-context';
import { useI18n } from '../frontend/i18n/react';
import { detailHistoryLocation, detailHistoryState } from '../frontend/navigation-state';
import { api } from '../frontend/services/api';
import type { SmtpCredential, SmtpRelay, SmtpRelayPayload } from '../frontend/types';

interface CredentialFormValues {
  username: string;
  password?: string;
}

type SmtpTab = 'credentials' | 'relays' | 'connection';

export default function SmtpCredentials() {
  const { message } = AntApp.useApp();
  const { locale, t } = useI18n();
  const { config } = useAppContext();
  const location = useLocation();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const [credentialForm] = Form.useForm<CredentialFormValues>();
  const [relayForm] = Form.useForm<SmtpRelayPayload>();
  const [primaryCredential, setPrimaryCredential] = useState<SmtpCredential | null>(null);
  const [credentials, setCredentials] = useState<SmtpCredential[]>([]);
  const [relays, setRelays] = useState<SmtpRelay[]>([]);
  const [loading, setLoading] = useState(true);
  const [credentialError, setCredentialError] = useState('');
  const [relayError, setRelayError] = useState('');
  const [connectionError, setConnectionError] = useState('');
  const [actionKey, setActionKey] = useState('');
  const [credentialOpen, setCredentialOpen] = useState(false);
  const [editingCredential, setEditingCredential] = useState<SmtpCredential | null>(null);
  const [relayOpen, setRelayOpen] = useState(false);
  const [editingRelay, setEditingRelay] = useState<SmtpRelay | null>(null);
  const requestedTab = searchParams.get('tab');
  const activeTab: SmtpTab = requestedTab === 'relays' || requestedTab === 'connection' ? requestedTab : 'credentials';
  const requestedCredentialId = positiveInteger(searchParams.get('credentialId'));
  const requestedRelayId = positiveInteger(searchParams.get('relayId'));
  const detail = useMemo(() => {
    if (requestedCredentialId) {
      const value = credentials.find((credential) => credential.id === requestedCredentialId);
      return value ? { type: 'credential' as const, value } : null;
    }
    if (requestedRelayId) {
      const value = relays.find((relay) => relay.id === requestedRelayId);
      return value ? { type: 'relay' as const, value } : null;
    }
    return null;
  }, [credentials, relays, requestedCredentialId, requestedRelayId]);

  const loadData = useCallback(async () => {
    setLoading(true);
    setCredentialError('');
    setRelayError('');
    setConnectionError('');
    const [primaryResult, credentialResult, relayResult] = await Promise.allSettled([
      api.smtpCredential(),
      api.smtpCredentials(),
      api.smtpRelays()
    ]);
    if (primaryResult.status === 'fulfilled') setPrimaryCredential(primaryResult.value.credential || null);
    else setConnectionError(errorMessage(primaryResult.reason, t));
    if (credentialResult.status === 'fulfilled') setCredentials(credentialResult.value.credentials || []);
    else setCredentialError(errorMessage(credentialResult.reason, t));
    if (relayResult.status === 'fulfilled') setRelays(relayResult.value.relays || []);
    else setRelayError(errorMessage(relayResult.reason, t));
    setLoading(false);
  }, [t]);

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

  function changeTab(key: string) {
    const next = new URLSearchParams(searchParams);
    next.set('tab', key);
    next.delete('credentialId');
    next.delete('relayId');
    setSearchParams(next, requestedCredentialId || requestedRelayId ? { replace: true, state: null } : undefined);
  }

  function openCredentialDetail(item: SmtpCredential) {
    if (!item.id) return;
    const next = new URLSearchParams(searchParams);
    next.set('tab', 'credentials');
    next.set('credentialId', String(item.id));
    next.delete('relayId');
    setSearchParams(next, {
      state: detailHistoryLocation(`${location.pathname}${location.search}`, 1)
    });
  }

  function openRelayDetail(relay: SmtpRelay) {
    const next = new URLSearchParams(searchParams);
    next.set('tab', 'relays');
    next.set('relayId', String(relay.id));
    next.delete('credentialId');
    setSearchParams(next, {
      state: detailHistoryLocation(`${location.pathname}${location.search}`, 1)
    });
  }

  function closeDetail() {
    const historyState = detailHistoryState(location.state);
    if (historyState) {
      navigate(-historyState.depth);
      return;
    }
    const next = new URLSearchParams(searchParams);
    next.delete('credentialId');
    next.delete('relayId');
    setSearchParams(next, { replace: true, state: null });
  }

  async function copyValue(value: string) {
    if (!value || value === '—') return;
    await navigator.clipboard.writeText(value);
    message.success(t('common.copied'));
  }

  function openCreateCredential() {
    setEditingCredential(null);
    credentialForm.resetFields();
    credentialForm.setFieldsValue({
      username: credentials.length === 0 ? primaryCredential?.username || config?.submission?.username || '' : '',
      password: ''
    });
    setCredentialOpen(true);
  }

  function openEditCredential(item: SmtpCredential) {
    setEditingCredential(item);
    credentialForm.resetFields();
    credentialForm.setFieldsValue({ username: item.username, password: '' });
    setCredentialOpen(true);
  }

  async function saveCredential() {
    const values = await credentialForm.validateFields();
    const key = editingCredential?.id ? `credential:save:${editingCredential.id}` : 'credential:create';
    setActionKey(key);
    try {
      await api.saveSmtpLoginCredential(values, editingCredential?.id);
      message.success(editingCredential ? t('actions.smtpUpdated') : t('actions.smtpCreated'));
      setCredentialOpen(false);
      setEditingCredential(null);
      credentialForm.resetFields();
      await loadData();
    } catch (error) {
      message.error(error instanceof Error ? error.message : t('common.error'));
    } finally {
      setActionKey('');
    }
  }

  async function deleteCredential(item: SmtpCredential) {
    if (!item.id) return;
    setActionKey(`credential:delete:${item.id}`);
    try {
      await api.deleteSmtpCredential(item.id);
      message.success(t('actions.smtpDeleted'));
      if (requestedCredentialId === item.id) closeDetail();
      await loadData();
    } catch (error) {
      message.error(error instanceof Error ? error.message : t('common.error'));
    } finally {
      setActionKey('');
    }
  }

  function openCreateRelay() {
    setEditingRelay(null);
    relayForm.resetFields();
    relayForm.setFieldsValue({
      name: '', host: '', port: 587, secure: false, username: '', password: '', helo: '', isDefault: relays.length === 0
    });
    setRelayOpen(true);
  }

  function openEditRelay(relay: SmtpRelay) {
    setEditingRelay(relay);
    relayForm.resetFields();
    relayForm.setFieldsValue({
      name: relay.name,
      host: relay.host,
      port: relay.port,
      secure: relay.secure,
      username: relay.username,
      password: '',
      helo: relay.helo,
      isDefault: relay.isDefault
    });
    setRelayOpen(true);
  }

  async function saveRelay() {
    const values = await relayForm.validateFields();
    const payload: SmtpRelayPayload = { ...values };
    if (editingRelay && !payload.password) delete payload.password;
    const key = editingRelay ? `relay:save:${editingRelay.id}` : 'relay:create';
    setActionKey(key);
    try {
      await api.saveSmtpRelay(payload, editingRelay?.id);
      message.success(editingRelay ? t('actions.smtpRelayUpdated') : t('actions.smtpRelayCreated'));
      setRelayOpen(false);
      setEditingRelay(null);
      relayForm.resetFields();
      await loadData();
    } catch (error) {
      message.error(error instanceof Error ? error.message : t('common.error'));
    } finally {
      setActionKey('');
    }
  }

  async function deleteRelay(relay: SmtpRelay) {
    setActionKey(`relay:delete:${relay.id}`);
    try {
      await api.deleteSmtpRelay(relay.id);
      message.success(t('actions.smtpRelayDeleted'));
      if (requestedRelayId === relay.id) closeDetail();
      await loadData();
    } catch (error) {
      message.error(error instanceof Error ? error.message : t('common.error'));
    } finally {
      setActionKey('');
    }
  }

  const credentialColumns: ColumnsType<SmtpCredential> = [
    {
      title: t('smtp.username'),
      dataIndex: 'username',
      render: (value: string) => <Typography.Text code>{value}</Typography.Text>
    },
    {
      title: t('smtp.password'),
      dataIndex: 'passwordSet',
      width: 140,
      render: (value?: boolean) => (
        <StatusPill tone={value ? 'success' : 'warning'}>{value ? t('smtp.passwordSet') : t('smtp.passwordEmpty')}</StatusPill>
      )
    },
    { title: t('tokens.createdAt'), dataIndex: 'createdAt', width: 190, render: (value) => formatDate(value, locale) },
    {
      title: t('common.actions'),
      width: 140,
      render: (_, item) => (
        <Space onClick={(event) => event.stopPropagation()}>
          <Button aria-label={`${t('common.edit')} ${item.username}`} icon={<EditOutlined />} onClick={() => openEditCredential(item)} disabled={!item.id} />
          <Popconfirm title={t('smtp.deleteConfirm')} onConfirm={() => void deleteCredential(item)} disabled={!item.id}>
            <Button aria-label={`${t('common.delete')} ${item.username}`} danger icon={<DeleteOutlined />} loading={actionKey === `credential:delete:${item.id}`} disabled={!item.id} />
          </Popconfirm>
        </Space>
      )
    }
  ];

  const relayColumns: ColumnsType<SmtpRelay> = [
    {
      title: t('smtpRelay.name'),
      dataIndex: 'name',
      render: (value: string, relay) => (
        <Space wrap><Typography.Text strong>{value}</Typography.Text>{relay.isDefault ? <StatusPill tone="success">{t('smtpRelay.default')}</StatusPill> : null}</Space>
      )
    },
    {
      title: t('smtpRelay.server'),
      render: (_, relay) => <Typography.Text code>{relay.host}:{relay.port}</Typography.Text>
    },
    { title: t('smtpRelay.username'), dataIndex: 'username', render: (value?: string) => value || '—' },
    {
      title: t('smtpRelay.password'),
      dataIndex: 'passwordSet',
      width: 140,
      render: (value: boolean) => <StatusPill tone={value ? 'success' : 'warning'}>{value ? t('smtpRelay.passwordSet') : t('smtpRelay.passwordEmpty')}</StatusPill>
    },
    {
      title: t('common.actions'),
      width: 140,
      render: (_, relay) => (
        <Space onClick={(event) => event.stopPropagation()}>
          <Button aria-label={`${t('common.edit')} ${relay.name}`} icon={<EditOutlined />} onClick={() => openEditRelay(relay)} />
          <Popconfirm title={t('smtpRelay.deleteConfirm')} onConfirm={() => void deleteRelay(relay)}>
            <Button aria-label={`${t('common.delete')} ${relay.name}`} danger icon={<DeleteOutlined />} loading={actionKey === `relay:delete:${relay.id}`} />
          </Popconfirm>
        </Space>
      )
    }
  ];

  const primaryAction = activeTab === 'credentials'
    ? <Button type="primary" icon={<PlusOutlined />} onClick={openCreateCredential} style={{ minHeight: 44 }}>{t('smtp.create')}</Button>
    : activeTab === 'relays'
      ? <Button type="primary" icon={<PlusOutlined />} onClick={openCreateRelay} style={{ minHeight: 44 }}>{t('smtpRelay.create')}</Button>
      : null;

  return (
    <Space direction="vertical" size={20} className="full-width">
      <PageHeader title={t('nav.smtp')} subtitle={t('smtp.connectionTitle')} extra={primaryAction} />
      <SectionCard>
        <Tabs
          activeKey={activeTab}
          onChange={changeTab}
          items={[
            {
              key: 'credentials',
              label: t('smtp.loginCredentialsTitle'),
              children: loading && !credentials.length ? <Skeleton active paragraph={{ rows: 5 }} /> : credentialError ? (
                <Alert type="error" showIcon message={credentialError} action={<Button icon={<ReloadOutlined />} onClick={() => void loadData()}>{t('common.refresh')}</Button>} />
              ) : credentials.length ? (
                <Table
                  rowKey={(item) => item.id || item.username}
                  columns={credentialColumns}
                  dataSource={credentials}
                  scroll={{ x: 760 }}
                  onRow={(item) => ({
                    onClick: () => openCredentialDetail(item),
                    style: { cursor: item.id ? 'pointer' : 'default' },
                    tabIndex: item.id ? 0 : -1,
                    onKeyDown: (event) => {
                      if (event.target !== event.currentTarget) return;
                      if (event.key === 'Enter' || event.key === ' ') {
                        event.preventDefault();
                        openCredentialDetail(item);
                      }
                    }
                  })}
                />
              ) : <EmptyState description={t('smtp.passwordUnavailable')} action={<Button icon={<PlusOutlined />} onClick={openCreateCredential}>{t('smtp.create')}</Button>} />
            },
            {
              key: 'relays',
              label: t('smtpRelay.title'),
              children: loading && !relays.length ? <Skeleton active paragraph={{ rows: 5 }} /> : relayError ? (
                <Alert type="error" showIcon message={relayError} action={<Button icon={<ReloadOutlined />} onClick={() => void loadData()}>{t('common.refresh')}</Button>} />
              ) : relays.length ? (
                <Table
                  rowKey="id"
                  columns={relayColumns}
                  dataSource={relays}
                  scroll={{ x: 860 }}
                  onRow={(relay) => ({
                    onClick: () => openRelayDetail(relay),
                    style: { cursor: 'pointer' },
                    tabIndex: 0,
                    onKeyDown: (event) => {
                      if (event.target !== event.currentTarget) return;
                      if (event.key === 'Enter' || event.key === ' ') {
                        event.preventDefault();
                        openRelayDetail(relay);
                      }
                    }
                  })}
                />
              ) : <EmptyState description={t('common.notConfigured')} action={<Button icon={<PlusOutlined />} onClick={openCreateRelay}>{t('smtpRelay.create')}</Button>} />
            },
            {
              key: 'connection',
              label: t('smtp.connectionTitle'),
              children: loading && !primaryCredential ? <Skeleton active /> : connectionError ? (
                <Alert type="error" showIcon message={connectionError} action={<Button icon={<ReloadOutlined />} onClick={() => void loadData()}>{t('common.refresh')}</Button>} />
              ) : (
                <Descriptions bordered column={1} size="small">
                  <Descriptions.Item label="SMTP Host">{copyable(config?.submission?.host || '—', copyValue, t('common.copy'))}</Descriptions.Item>
                  <Descriptions.Item label="SMTP Port">
                    <Space wrap>{(config?.submission?.ports || []).map((item) => <StatusPill key={item.port} tone="info">{item.port} · {item.protocol}</StatusPill>)}</Space>
                  </Descriptions.Item>
                  <Descriptions.Item label="TLS / SSL">{config?.submission?.tls ? 'TLS' : 'STARTTLS'}</Descriptions.Item>
                  <Descriptions.Item label={t('smtp.username')}>{copyable(primaryCredential?.username || config?.submission?.username || '—', copyValue, t('common.copy'))}</Descriptions.Item>
                  <Descriptions.Item label={t('smtp.password')}>
                    <Typography.Text type="secondary">{t('smtp.resetToCopy')}</Typography.Text>
                  </Descriptions.Item>
                </Descriptions>
              )
            }
          ]}
        />
      </SectionCard>

      <Drawer
        title={editingCredential ? t('smtp.editTitle') : t('smtp.createTitle')}
        width={560}
        open={credentialOpen}
        onClose={() => setCredentialOpen(false)}
        destroyOnHidden
        footer={<DrawerFooter t={t} loading={actionKey === 'credential:create' || actionKey.startsWith('credential:save:')} onCancel={() => setCredentialOpen(false)} onSave={() => void saveCredential()} />}
      >
        <Alert type="info" showIcon message={locale.startsWith('en') ? 'Saved SMTP passwords are never returned. Leave the password blank when editing to keep it unchanged.' : '已保存的 SMTP 密码不会返回。编辑时留空即可保留原密码。'} style={{ marginBottom: 20 }} />
        <Form form={credentialForm} layout="vertical">
          <Form.Item name="username" label={t('smtp.username')} rules={[{ required: true, message: t('smtp.usernameRequired') }]}><Input autoComplete="off" /></Form.Item>
          <Form.Item name="password" label={t('smtp.password')} rules={[{ required: !editingCredential, message: t('smtp.passwordRequired') }]}>
            <Input.Password autoComplete="new-password" />
          </Form.Item>
          <Button icon={<ReloadOutlined />} onClick={() => credentialForm.setFieldValue('password', randomPassword())}>{t('smtp.regenerate')}</Button>
        </Form>
      </Drawer>

      <Drawer
        title={editingRelay ? t('smtpRelay.editTitle') : t('smtpRelay.createTitle')}
        width={600}
        open={relayOpen}
        onClose={() => setRelayOpen(false)}
        destroyOnHidden
        footer={<DrawerFooter t={t} loading={actionKey === 'relay:create' || actionKey.startsWith('relay:save:')} onCancel={() => setRelayOpen(false)} onSave={() => void saveRelay()} />}
      >
        <Alert type="info" showIcon message={locale.startsWith('en') ? 'Saved relay passwords are write-only. Leave the password blank when editing to keep it unchanged.' : '已保存的中继密码为只写字段。编辑时留空即可保留原密码。'} style={{ marginBottom: 20 }} />
        <Form form={relayForm} layout="vertical">
          <Form.Item name="name" label={t('smtpRelay.name')} rules={[{ required: true, message: t('smtpRelay.nameRequired') }]}><Input autoComplete="off" placeholder="Amazon SES" /></Form.Item>
          <Form.Item name="host" label="SMTP Host" rules={[{ required: true, message: t('smtpRelay.hostRequired') }]}><Input autoComplete="off" placeholder="email-smtp.us-east-1.amazonaws.com" /></Form.Item>
          <Form.Item name="port" label="SMTP Port" rules={[{ required: true, message: t('smtpRelay.portRequired') }]}><InputNumber min={1} max={65535} className="full-width" /></Form.Item>
          <Form.Item name="secure" label="SSL/TLS" valuePropName="checked"><Switch /></Form.Item>
          <Form.Item name="username" label={t('smtpRelay.username')}><Input autoComplete="off" /></Form.Item>
          <Form.Item name="password" label={t('smtpRelay.password')}><Input.Password autoComplete="new-password" /></Form.Item>
          <Button icon={<ReloadOutlined />} onClick={() => relayForm.setFieldValue('password', randomPassword())}>{t('smtpRelay.generatePassword')}</Button>
          <Form.Item name="helo" label="HELO" extra={t('smtpRelay.heloExtra')} style={{ marginTop: 20 }}><Input autoComplete="off" placeholder={config?.mailHostname || 'mail.example.com'} /></Form.Item>
          <Form.Item name="isDefault" label={t('smtpRelay.default')} valuePropName="checked"><Switch /></Form.Item>
        </Form>
      </Drawer>

      <Drawer title={detail?.type === 'credential' ? detail.value.username : detail?.type === 'relay' ? detail.value.name : t('nav.smtp')} width={480} open={Boolean(requestedCredentialId || requestedRelayId)} onClose={closeDetail}>
        {loading && !detail ? <Skeleton active paragraph={{ rows: 5 }} /> : detail?.type === 'credential' ? (
          <Descriptions bordered column={1} size="small">
            <Descriptions.Item label={t('smtp.username')}><Typography.Text code>{detail.value.username}</Typography.Text></Descriptions.Item>
            <Descriptions.Item label={t('smtp.password')}><StatusPill tone={detail.value.passwordSet ? 'success' : 'warning'}>{detail.value.passwordSet ? t('smtp.passwordSet') : t('smtp.passwordEmpty')}</StatusPill></Descriptions.Item>
            <Descriptions.Item label={t('tokens.createdAt')}>{formatDate(detail.value.createdAt, locale)}</Descriptions.Item>
          </Descriptions>
        ) : detail?.type === 'relay' ? (
          <Descriptions bordered column={1} size="small">
            <Descriptions.Item label={t('smtpRelay.server')}><Typography.Text code>{detail.value.host}:{detail.value.port}</Typography.Text></Descriptions.Item>
            <Descriptions.Item label="TLS">{detail.value.secure ? 'SSL/TLS' : 'STARTTLS / Plain'}</Descriptions.Item>
            <Descriptions.Item label={t('smtpRelay.username')}>{detail.value.username || '—'}</Descriptions.Item>
            <Descriptions.Item label={t('smtpRelay.password')}><StatusPill tone={detail.value.passwordSet ? 'success' : 'warning'}>{detail.value.passwordSet ? t('smtpRelay.passwordSet') : t('smtpRelay.passwordEmpty')}</StatusPill></Descriptions.Item>
            <Descriptions.Item label="HELO">{detail.value.helo || '—'}</Descriptions.Item>
          </Descriptions>
        ) : requestedCredentialId && credentialError ? (
          <Alert type="error" showIcon message={credentialError} action={<Button icon={<ReloadOutlined />} onClick={() => void loadData()}>{t('common.refresh')}</Button>} />
        ) : requestedRelayId && relayError ? (
          <Alert type="error" showIcon message={relayError} action={<Button icon={<ReloadOutlined />} onClick={() => void loadData()}>{t('common.refresh')}</Button>} />
        ) : requestedCredentialId || requestedRelayId ? <EmptyState description={t('common.notFound')} /> : null}
      </Drawer>
    </Space>
  );
}

function DrawerFooter({ t, loading, onCancel, onSave }: { t: (key: string) => string; loading: boolean; onCancel: () => void; onSave: () => void }) {
  return <Space style={{ display: 'flex', justifyContent: 'flex-end' }}><Button onClick={onCancel}>{t('common.cancel')}</Button><Button type="primary" loading={loading} onClick={onSave}>{t('common.save')}</Button></Space>;
}

function randomPassword() {
  const bytes = new Uint8Array(24);
  crypto.getRandomValues(bytes);
  return btoa(String.fromCharCode(...bytes)).replace(/[+/=]/g, '').slice(0, 28);
}

function copyable(value: string, onCopy: (value: string) => void, label: string) {
  return <Space><Typography.Text code className="inline-code-value">{value}</Typography.Text><Button aria-label={`${label} ${value}`} icon={<CopyOutlined />} onClick={() => void onCopy(value)} /></Space>;
}

function formatDate(value: string | undefined, locale: string) {
  if (!value) return '—';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return '—';
  return new Intl.DateTimeFormat(locale, {
    year: 'numeric', month: '2-digit', day: '2-digit',
    hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false
  }).format(date);
}

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

function errorMessage(error: unknown, t: (key: string) => string) {
  return error instanceof Error ? error.message : t('common.error');
}
