import {
  ArrowRightOutlined,
  CheckCircleOutlined,
  ExclamationCircleOutlined
} from '@ant-design/icons';
import {
  Alert,
  Button,
  Col,
  List,
  Result,
  Row,
  Segmented,
  Skeleton,
  Space,
  Typography
} from 'antd';
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';

import { EmptyState } from '../components/common/EmptyState';
import { MetricCard } from '../components/common/MetricCard';
import { PageHeader } from '../components/common/PageHeader';
import { SectionCard } from '../components/common/SectionCard';
import { StatusPill, type StatusTone } from '../components/common/StatusPill';
import { buildEngagementSummary } from '../frontend/analytics-model.js';
import { buildDomainHealth } from '../frontend/domain-model.js';
import { useAppContext } from '../frontend/app-context';
import { useI18n } from '../frontend/i18n/react';
import { api } from '../frontend/services/api';
import type { Analytics, ApiToken, Domain, SmtpCredential, WebhookDelivery } from '../frontend/types';

const DashboardCharts = lazy(() => import('./DashboardCharts'));

type RangeDays = 1 | 7 | 30;
type AnalysisSection = 'delivery' | 'engagement';
type DashboardDependency = 'smtp' | 'apiTokens' | 'webhooks';
type CredentialReadiness = 'ready' | 'missing' | 'unknown';

interface DashboardData {
  range: RangeDays;
  analytics: Analytics;
  domains: Domain[];
  smtpCredential?: SmtpCredential | null;
  apiTokens?: ApiToken[];
  failedWebhooks?: WebhookDelivery[];
}

interface ActionLink {
  label: string;
  path: string;
}

interface ActionItem {
  key: string;
  title: string;
  description: string;
  tone: StatusTone;
  actions: ActionLink[];
}

interface ReadinessItem {
  title: string;
  done: boolean;
  unknown: boolean;
  actions: Array<{ label?: string; path: string }>;
}

export default function Dashboard() {
  const { config } = useAppContext();
  const { locale } = useI18n();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const range = normalizeRange(searchParams.get('range'));
  const analysisSection = normalizeAnalysisSection(searchParams.get('analysis'));
  const [data, setData] = useState<DashboardData | null>(null);
  const [loading, setLoading] = useState(true);
  const [coreError, setCoreError] = useState<{ range: RangeDays; message: string } | null>(null);
  const [dependencyErrors, setDependencyErrors] = useState<Partial<Record<DashboardDependency, string>>>({});
  const requestId = useRef(0);
  const copy = locale.startsWith('en') ? enCopy : zhCopy;

  const load = useCallback(async () => {
    const currentRequest = ++requestId.current;
    setLoading(true);
    setCoreError(null);
    try {
      const [analyticsResult, domainsResult, credentialResult, tokensResult, webhooksResult] = await Promise.allSettled([
        api.analytics(range),
        api.domains(),
        api.smtpCredential(),
        api.apiTokens(),
        api.webhookDeliveries({ status: 'dead', limit: 5 })
      ]);
      if (currentRequest !== requestId.current) return;

      const coreErrors = [
        analyticsResult.status === 'rejected' ? copy.dependencyError(copy.analyticsDependency, analyticsResult.reason) : '',
        domainsResult.status === 'rejected' ? copy.dependencyError(copy.domainsDependency, domainsResult.reason) : ''
      ].filter(Boolean);
      setCoreError(coreErrors.length ? { range, message: coreErrors.join('\n') } : null);

      const nextDependencyErrors: Partial<Record<DashboardDependency, string>> = {};
      if (credentialResult.status === 'rejected') nextDependencyErrors.smtp = errorMessage(credentialResult.reason, copy.loadFailed);
      if (tokensResult.status === 'rejected') nextDependencyErrors.apiTokens = errorMessage(tokensResult.reason, copy.loadFailed);
      if (webhooksResult.status === 'rejected') nextDependencyErrors.webhooks = errorMessage(webhooksResult.reason, copy.loadFailed);
      setDependencyErrors(nextDependencyErrors);

      setData((current) => {
        const currentRangeData = current?.range === range ? current : null;
        const analytics = analyticsResult.status === 'fulfilled' ? analyticsResult.value.analytics : currentRangeData?.analytics;
        const domains = domainsResult.status === 'fulfilled' ? domainsResult.value.domains : current?.domains;
        if (!analytics || !domains) return current;
        return {
          range,
          analytics,
          domains,
          smtpCredential: credentialResult.status === 'fulfilled' ? credentialResult.value.credential : current?.smtpCredential,
          apiTokens: tokensResult.status === 'fulfilled' ? tokensResult.value.tokens : current?.apiTokens,
          failedWebhooks: webhooksResult.status === 'fulfilled' ? webhooksResult.value.deliveries : current?.failedWebhooks
        };
      });
    } catch (reason) {
      if (currentRequest === requestId.current) {
        setCoreError({ range, message: reason instanceof Error ? reason.message : copy.loadFailed });
      }
    } finally {
      if (currentRequest === requestId.current) setLoading(false);
    }
  }, [copy, range]);

  useEffect(() => {
    void load();
    return () => { requestId.current += 1; };
  }, [load]);

  const currentData = data?.range === range ? data : null;
  const error = coreError?.range === range ? coreError.message : '';
  const operationalData = useMemo(() => currentData ? {
    ...currentData,
    smtpCredential: dependencyErrors.smtp ? undefined : currentData.smtpCredential,
    apiTokens: dependencyErrors.apiTokens ? undefined : currentData.apiTokens,
    failedWebhooks: dependencyErrors.webhooks ? undefined : currentData.failedWebhooks
  } : null, [currentData, dependencyErrors.apiTokens, dependencyErrors.smtp, dependencyErrors.webhooks]);
  const actions = useMemo(() => operationalData ? buildActionItems(operationalData, copy) : [], [copy, operationalData]);
  const dependencyErrorEntries = Object.entries(dependencyErrors) as Array<[DashboardDependency, string]>;
  const actionStateUnknown = dependencyErrorEntries.length > 0;

  function changeRange(value: string | number) {
    const next = new URLSearchParams(searchParams);
    next.set('range', String(value));
    setSearchParams(next);
  }

  function changeAnalysisSection(value: AnalysisSection) {
    const next = new URLSearchParams(searchParams);
    if (value === 'delivery') next.delete('analysis');
    else next.set('analysis', value);
    setSearchParams(next);
  }

  if (!currentData && !error) {
    return (
      <Space direction="vertical" size={20} className="full-width" aria-label={copy.loading}>
        <Skeleton active title={{ width: '28%' }} paragraph={{ rows: 2 }} />
        <Row gutter={[16, 16]}>{[0, 1, 2, 3].map((key) => <Col xs={24} sm={12} xl={6} key={key}><Skeleton.Node active style={{ width: '100%' }} /></Col>)}</Row>
        <SectionCard><Skeleton active paragraph={{ rows: 8 }} /></SectionCard>
      </Space>
    );
  }

  if (error && !currentData) {
    return (
      <Result
        status="error"
        title={copy.loadFailed}
        subTitle={error}
        extra={<Button type="primary" onClick={() => void load()}>{copy.retry}</Button>}
      />
    );
  }

  if (!currentData) return null;

  const { analytics, domains } = currentData;
  const summary = analytics.summary;
  const engagement = buildEngagementSummary(analytics);
  const failuresAndDelays = Number(summary.terminalFailed || summary.failed || 0)
    + Number(summary.deferred || 0)
    + Number(summary.pending || 0);

  return (
    <Space direction="vertical" size={20} className="full-width">
      {config?.usingDefaultAdminPassword ? (
        <Alert type="warning" showIcon message={copy.defaultPassword} description={copy.defaultPasswordDescription} />
      ) : null}

      {error ? <Alert type="error" showIcon message={copy.partialFailure} description={error} action={<Button size="small" onClick={() => void load()}>{copy.retry}</Button>} /> : null}

      {dependencyErrorEntries.length ? (
        <Alert
          type="warning"
          showIcon
          message={copy.dependencyFailureTitle}
          description={
            <Space direction="vertical" size={2}>
              {dependencyErrorEntries.map(([dependency, detail]) => (
                <Typography.Text key={dependency}>{copy.dependencyLabel(dependency)}: {detail}</Typography.Text>
              ))}
            </Space>
          }
          action={<Button size="small" loading={loading} onClick={() => void load()}>{copy.retry}</Button>}
        />
      ) : null}

      <PageHeader
        title={copy.title}
        subtitle={copy.subtitle}
        extra={
          <Segmented
            aria-label={copy.rangeLabel}
            value={range}
            onChange={changeRange}
            options={[
              { label: copy.last24Hours, value: 1 },
              { label: copy.last7Days, value: 7 },
              { label: copy.last30Days, value: 30 }
            ]}
          />
        }
      />

      <Row gutter={[16, 16]}>
        <Col xs={24} sm={12} xl={6}>
          <MetricCard label={copy.sent} value={summary.total || 0} hint={`${summary.recipients || 0} ${copy.recipients}`} />
        </Col>
        <Col xs={24} sm={12} xl={6}>
          <MetricCard label={copy.deliveryRate} value={`${summary.deliveryRate || 0}%`} hint={`${summary.delivered || 0} ${copy.delivered}`} />
        </Col>
        <Col xs={24} sm={12} xl={6}>
          <MetricCard
            label={copy.failuresAndDelays}
            value={failuresAndDelays}
            tone={failuresAndDelays ? 'danger' : 'default'}
            hint={`${summary.terminalFailed || summary.failed || 0} ${copy.failed} · ${summary.deferred || 0} ${copy.deferred}`}
          />
        </Col>
        <Col xs={24} sm={12} xl={6}>
          <MetricCard
            label={copy.opensAndClicks}
            value={`${engagement.openRate}% / ${engagement.clickRate}%`}
            hint={`${engagement.uniqueOpens} ${copy.opens} · ${engagement.uniqueClicks} ${copy.clicks}`}
          />
        </Col>
      </Row>

      <SectionCard
        title={copy.actionNeeded}
        extra={actions.length
          ? <StatusPill tone="warning">{actions.length} {copy.items}</StatusPill>
          : actionStateUnknown
            ? <StatusPill tone="warning">{copy.statusUnknown}</StatusPill>
            : <StatusPill tone="success">{copy.allClear}</StatusPill>}
      >
        {actions.length ? (
          <List
            dataSource={actions}
            renderItem={(item) => (
              <List.Item
                actions={item.actions.map((action) => (
                  <Button key={`${item.key}:${action.path}`} type="link" onClick={() => navigate(action.path)}>
                    {action.label} <ArrowRightOutlined />
                  </Button>
                ))}
              >
                <List.Item.Meta
                  avatar={<ExclamationCircleOutlined aria-hidden style={{ color: item.tone === 'error' ? '#dc2626' : '#d97706', fontSize: 20 }} />}
                  title={<Space wrap><Typography.Text strong>{item.title}</Typography.Text><StatusPill tone={item.tone}>{copy.needsAction}</StatusPill></Space>}
                  description={item.description}
                />
              </List.Item>
            )}
          />
        ) : actionStateUnknown ? (
          <EmptyState description={copy.actionStatusUnknown} icon={<ExclamationCircleOutlined style={{ color: '#d97706' }} />} />
        ) : (
          <EmptyState description={copy.noActionNeeded} icon={<CheckCircleOutlined style={{ color: '#16a34a' }} />} />
        )}
      </SectionCard>

      {!summary.total ? <ReadinessChecklist domains={domains} credential={operationalData?.smtpCredential} apiTokens={operationalData?.apiTokens} onNavigate={navigate} copy={copy} /> : null}

      <Suspense fallback={<SectionCard><Skeleton active paragraph={{ rows: 8 }} /></SectionCard>}>
        <DashboardCharts
          analytics={analytics}
          copy={copy}
          activeSection={analysisSection}
          onSectionChange={changeAnalysisSection}
        />
      </Suspense>
    </Space>
  );
}

function ReadinessChecklist({
  domains,
  credential,
  apiTokens,
  onNavigate,
  copy
}: {
  domains: Domain[];
  credential?: SmtpCredential | null;
  apiTokens?: ApiToken[];
  onNavigate: (path: string) => void;
  copy: typeof zhCopy;
}) {
  const hasDomain = domains.length > 0;
  const dnsReady = domains.some((domain) => buildDomainHealth(domain).status === 'success');
  const credentialStatus = getCredentialReadiness(credential, apiTokens);
  const items: ReadinessItem[] = [
    { title: copy.addDomain, done: hasDomain, unknown: false, actions: [{ path: '/domains' }] },
    { title: copy.configureDns, done: dnsReady, unknown: false, actions: [{ path: hasDomain ? `/domains/${domains[0].id}/dns` : '/domains' }] },
    {
      title: copy.createCredential,
      done: credentialStatus === 'ready',
      unknown: credentialStatus === 'unknown',
      actions: [
        { label: copy.smtpEntry, path: '/integrations/smtp' },
        { label: copy.apiKeyEntry, path: '/integrations/api-keys' }
      ]
    },
    { title: copy.sendTest, done: false, unknown: false, actions: [{ path: hasDomain ? `/domains/${domains[0].id}/sending` : '/domains' }] }
  ];
  return (
    <SectionCard title={copy.getReady} extra={<Typography.Text type="secondary">{copy.getReadyHint}</Typography.Text>}>
      <List
        dataSource={items}
        renderItem={(item, index) => (
          <List.Item actions={item.actions.map((action) => <Button key={action.path} type={index === 0 && !item.done ? 'primary' : 'default'} onClick={() => onNavigate(action.path)}>{action.label || (item.done ? copy.review : copy.start)}</Button>)}>
            <List.Item.Meta
              avatar={item.done
                ? <CheckCircleOutlined style={{ color: '#16a34a', fontSize: 20 }} />
                : item.unknown
                  ? <StatusPill tone="warning">{copy.statusUnknown}</StatusPill>
                  : <StatusPill tone="neutral">{index + 1}</StatusPill>}
              title={<Typography.Text delete={item.done}>{item.title}</Typography.Text>}
            />
          </List.Item>
        )}
      />
    </SectionCard>
  );
}

function buildActionItems(data: DashboardData, copy: typeof zhCopy): ActionItem[] {
  const unhealthy = data.domains.filter((domain) => buildDomainHealth(domain).status !== 'success');
  const recentFailures = data.analytics.recentFailures || [];
  const items: ActionItem[] = [];
  if (unhealthy.length) {
    items.push({ key: 'dns', title: copy.dnsNotReady(unhealthy.length), description: copy.dnsNotReadyHint, tone: 'warning', actions: [{ label: copy.reviewDomains, path: '/domains?status=error' }] });
  }
  if (recentFailures.length) {
    items.push({ key: 'failures', title: copy.recentFailures(recentFailures.length), description: recentFailures[0]?.detail || copy.recentFailuresHint, tone: 'error', actions: [{ label: copy.inspectActivity, path: '/activity?status=failed' }] });
  }
  if (data.failedWebhooks?.length) {
    const firstFailedDelivery = data.failedWebhooks[0];
    const webhookPath = firstFailedDelivery?.webhookId
      ? `/integrations/webhooks?webhookId=${firstFailedDelivery.webhookId}&deliveryStatus=dead`
      : '/integrations/webhooks?deliveryStatus=dead';
    items.push({ key: 'webhooks', title: copy.webhookFailures(data.failedWebhooks.length), description: copy.webhookFailuresHint, tone: 'error', actions: [{ label: copy.reviewWebhooks, path: webhookPath }] });
  }
  if (getCredentialReadiness(data.smtpCredential, data.apiTokens) === 'missing') {
    items.push({
      key: 'credential',
      title: copy.missingCredential,
      description: copy.missingCredentialHint,
      tone: 'warning',
      actions: [
        { label: copy.configureSmtp, path: '/integrations/smtp' },
        { label: copy.createApiKey, path: '/integrations/api-keys' }
      ]
    });
  }
  return items;
}

function getCredentialReadiness(smtpCredential?: SmtpCredential | null, apiTokens?: ApiToken[]): CredentialReadiness {
  const smtpReady = Boolean(smtpCredential?.passwordSet);
  const apiReady = Boolean(apiTokens?.some((token) => token.status === 'active' && token.scopes.includes('send')));
  if (smtpReady || apiReady) return 'ready';
  if (smtpCredential === undefined || apiTokens === undefined) return 'unknown';
  return 'missing';
}

function errorMessage(reason: unknown, fallback: string) {
  return reason instanceof Error ? reason.message : fallback;
}

function normalizeRange(value: string | null): RangeDays {
  if (value === '1') return 1;
  if (value === '30') return 30;
  return 7;
}

function normalizeAnalysisSection(value: string | null): AnalysisSection {
  return value === 'engagement' ? 'engagement' : 'delivery';
}

const zhCopy = {
  title: '运行概览', subtitle: '从投递健康开始，快速定位需要处理的问题。', loading: '正在加载运行概览', loadFailed: '概览加载失败', retry: '重试', rangeLabel: '统计时间范围', last24Hours: '24 小时', last7Days: '7 天', last30Days: '30 天',
  sent: '发送量', recipients: '位收件人', deliveryRate: '送达率', delivered: '已送达', failuresAndDelays: '失败 / 延迟', failed: '失败', deferred: '延迟', opensAndClicks: '打开 / 点击', opens: '打开', clicks: '点击',
  actionNeeded: '需要处理', items: '项', allClear: '状态正常', statusUnknown: '状态未知', needsAction: '需要处理', noActionNeeded: '当前没有检测到需要处理的投递问题。', actionStatusUnknown: '部分运维状态暂时无法获取，请重试后再确认。', partialFailure: '部分数据刷新失败', dependencyFailureTitle: '部分运维状态获取失败', dependencyLabel: (dependency: DashboardDependency) => ({ smtp: 'SMTP 凭据', apiTokens: 'API 密钥', webhooks: 'Webhook 失败投递' })[dependency], dependencyError: (label: string, reason: unknown) => `${label}：${errorMessage(reason, '加载失败')}`, analyticsDependency: '投递统计', domainsDependency: '域名状态', defaultPassword: '当前仍在使用默认管理员密码', defaultPasswordDescription: '请修改部署环境中的 ADMIN_PASSWORD，并重启 MailHub 服务使新密码生效。',
  getReady: '发送就绪清单', getReadyHint: '完成以下步骤后即可进行首次测试发送', addDomain: '添加发信域名', configureDns: '配置并验证 DNS', createCredential: '创建 SMTP 或 API 凭据', smtpEntry: 'SMTP', apiKeyEntry: 'API 密钥', sendTest: '发送测试邮件', review: '查看', start: '开始',
  deliveryQuality: '投递质量', engagementAnalysis: '互动分析', deliveryTrend: '发送与送达趋势', engagementTrend: '打开与点击趋势', domainRanking: '域名发送排行', topLinks: '热门链接', link: '链接', uniqueClicks: '独立点击', noDeliveryData: '当前范围暂无发送数据', noDomainData: '暂无域名发送数据', noEngagementData: '暂无互动数据',
  dnsNotReady: (count: number) => `${count} 个域名的 DNS 尚未就绪`, dnsNotReadyHint: '认证记录不完整可能导致投递失败或进入垃圾箱。', reviewDomains: '处理域名', recentFailures: (count: number) => `最近发现 ${count} 条发送失败`, recentFailuresHint: '请检查投递响应和队列日志。', inspectActivity: '查看活动', webhookFailures: (count: number) => `${count} 条 Webhook 投递已停止重试`, webhookFailuresHint: '请检查回调地址、签名校验和服务可用性。', reviewWebhooks: '检查 Webhooks', missingCredential: '尚未创建可用的发送凭据', missingCredentialHint: '配置 SMTP 凭据或创建具备 send 权限的 API 密钥后，应用即可发送邮件。', configureSmtp: '配置 SMTP', createApiKey: '创建 API 密钥'
};

const enCopy: typeof zhCopy = {
  title: 'Operations overview', subtitle: 'Start with delivery health and move directly to issues that need attention.', loading: 'Loading operations overview', loadFailed: 'Unable to load overview', retry: 'Retry', rangeLabel: 'Analytics range', last24Hours: '24 hours', last7Days: '7 days', last30Days: '30 days',
  sent: 'Sent', recipients: 'recipients', deliveryRate: 'Delivery rate', delivered: 'Delivered', failuresAndDelays: 'Failed / delayed', failed: 'Failed', deferred: 'Delayed', opensAndClicks: 'Opens / clicks', opens: 'Opens', clicks: 'Clicks',
  actionNeeded: 'Action needed', items: 'items', allClear: 'All clear', statusUnknown: 'Status unknown', needsAction: 'Needs action', noActionNeeded: 'No delivery issues currently require attention.', actionStatusUnknown: 'Some operational status is unavailable. Retry before treating the environment as healthy.', partialFailure: 'Some data could not be refreshed', dependencyFailureTitle: 'Some operational status could not be loaded', dependencyLabel: (dependency: DashboardDependency) => ({ smtp: 'SMTP credentials', apiTokens: 'API keys', webhooks: 'Failed webhook deliveries' })[dependency], dependencyError: (label: string, reason: unknown) => `${label}: ${errorMessage(reason, 'Unable to load')}`, analyticsDependency: 'Delivery analytics', domainsDependency: 'Domain status', defaultPassword: 'The default administrator password is still in use', defaultPasswordDescription: 'Update ADMIN_PASSWORD in the deployment environment, then restart MailHub for the new password to take effect.',
  getReady: 'Sending readiness', getReadyHint: 'Complete these steps before your first test send', addDomain: 'Add a sending domain', configureDns: 'Configure and verify DNS', createCredential: 'Create an SMTP or API credential', smtpEntry: 'SMTP', apiKeyEntry: 'API key', sendTest: 'Send a test email', review: 'Review', start: 'Start',
  deliveryQuality: 'Delivery quality', engagementAnalysis: 'Engagement', deliveryTrend: 'Sending and delivery trend', engagementTrend: 'Open and click trend', domainRanking: 'Domain ranking', topLinks: 'Top links', link: 'Link', uniqueClicks: 'Unique clicks', noDeliveryData: 'No sending data in this range', noDomainData: 'No domain sending data', noEngagementData: 'No engagement data',
  dnsNotReady: (count: number) => `${count} domains have incomplete DNS`, dnsNotReadyHint: 'Incomplete authentication records can cause delivery failures or spam placement.', reviewDomains: 'Review domains', recentFailures: (count: number) => `${count} recent sends failed`, recentFailuresHint: 'Inspect the delivery response and queue log.', inspectActivity: 'Inspect activity', webhookFailures: (count: number) => `${count} webhook deliveries stopped retrying`, webhookFailuresHint: 'Check the callback endpoint, signature validation, and service availability.', reviewWebhooks: 'Review webhooks', missingCredential: 'No usable sending credential', missingCredentialHint: 'Configure SMTP or create an API key with the send scope before applications send email.', configureSmtp: 'Configure SMTP', createApiKey: 'Create API key'
};
