import { App as AntApp, ConfigProvider } from 'antd';
import { render, screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
import { afterEach, describe, expect, it, vi } from 'vitest';

import { AppContext, type AppContextValue } from '../../src/frontend/app-context';
import { I18nProvider } from '../../src/frontend/i18n/react';
import { api } from '../../src/frontend/services/api';
import { mailhubTheme } from '../../src/frontend/theme';
import AdminPage from '../../src/pages/Admin';
import type { AdminResourceInventory, AdminUser, Domain, RuntimeConfig } from '../../src/frontend/types';

describe('Admin resource migration', () => {
  afterEach(() => vi.restoreAllMocks());

  it('submits a domain transfer after selecting the domain and target user', async () => {
    const user = userEvent.setup();
    const transferDomain = vi.spyOn(api, 'transferAdminDomain').mockResolvedValue({ domain });
    vi.spyOn(api, 'adminUsers').mockResolvedValue({ users });
    vi.spyOn(api, 'adminResources').mockResolvedValue({ inventory });

    renderAdminResourcesRoute();

    const transferCard = (await screen.findByText('迁移域名')).closest('.ant-card');
    expect(transferCard).not.toBeNull();
    await selectOption(user, within(transferCard!).getByLabelText('域名'), 'taobiba.com · chendeben');
    await selectOption(user, within(transferCard!).getByLabelText('目标用户'), 'chan (#7)');
    await user.click(within(transferCard!).getByRole('button', { name: '执行迁移' }));

    const dialog = await screen.findByRole('dialog');
    expect(dialog.textContent).toContain('确认迁移该域名？');
    await user.click(within(dialog).getByRole('button', { name: /确\s*认/ }));

    await waitFor(() => expect(transferDomain).toHaveBeenCalledWith(12, {
      targetUserId: 7,
      dnsCredentialMode: 'domain_only'
    }));
  });

  it('submits a DNS credential transfer after confirming the action', async () => {
    const user = userEvent.setup();
    const transferCredential = vi.spyOn(api, 'transferAdminDnsCredential').mockResolvedValue({
      credential: inventory.users[0].dnsCredentials[0]
    });
    vi.spyOn(api, 'adminUsers').mockResolvedValue({ users });
    vi.spyOn(api, 'adminResources').mockResolvedValue({ inventory });

    renderAdminResourcesRoute();

    const transferCard = (await screen.findByText('迁移 DNS 凭据')).closest('.ant-card');
    expect(transferCard).not.toBeNull();
    await selectOption(user, within(transferCard!).getByLabelText('DNS 凭据'), 'DNSPod · taobiba.com · chendeben');
    await selectOption(user, within(transferCard!).getByLabelText('目标用户'), 'chan (#7)');
    await user.click(within(transferCard!).getByRole('button', { name: '执行迁移' }));

    const dialog = await screen.findByRole('dialog');
    expect(dialog.textContent).toContain('确认迁移该 DNS 凭据？');
    await user.click(within(dialog).getByRole('button', { name: /确\s*认/ }));

    await waitFor(() => expect(transferCredential).toHaveBeenCalledWith(8, { targetUserId: 7 }));
  });
});

async function selectOption(user: ReturnType<typeof userEvent.setup>, input: HTMLElement, option: string) {
  await user.click(input);
  await user.click(await screen.findByText(option, { selector: '.ant-select-item-option-content' }));
}

function renderAdminResourcesRoute() {
  const router = createMemoryRouter([{ path: '/admin/:section', element: <AdminPage /> }], {
    initialEntries: ['/admin/resources']
  });

  return render(
    <ConfigProvider theme={{ ...mailhubTheme, token: { ...mailhubTheme.token, motion: false } }}>
      <AntApp>
        <I18nProvider>
          <AppContext.Provider value={appContext}>
            <RouterProvider router={router} />
          </AppContext.Provider>
        </I18nProvider>
      </AntApp>
    </ConfigProvider>
  );
}

const resourceCounts = {
  domains: 1,
  dnsCredentials: 1,
  apiTokens: 0,
  inboundMailboxes: 0,
  inboundMessages: 0,
  sendEvents: 0,
  smtpCredential: 0
};

const users: AdminUser[] = [
  { id: 1, username: 'chendeben', email: 'owner@example.test', role: 'admin', status: 'active', resourceCounts },
  { id: 7, username: 'chan', email: 'chan@example.test', role: 'user', status: 'active', resourceCounts }
];

const domain: Domain = {
  id: 12,
  userId: 1,
  dnsCredentialId: 8,
  smtpRelayId: null,
  domain: 'taobiba.com',
  selector: 'mailhub',
  verificationToken: 'verify-token',
  dkimPublic: 'public-key',
  senderHost: 'mail.taobiba.com',
  sendingIp: '192.0.2.10',
  spfExtra: '',
  dmarcPolicy: 'none',
  dmarcRua: '',
  catchAllAddress: '',
  mailboxSignupEnabled: false,
  status: {},
  createdAt: '2026-07-19T00:00:00.000Z',
  updatedAt: '2026-07-19T00:00:00.000Z'
};

const inventory: AdminResourceInventory = {
  users: [
    {
      user: users[0],
      domains: [domain],
      dnsCredentials: [{
        id: 8,
        userId: 1,
        name: 'DNSPod',
        provider: 'dnspod',
        zoneName: 'taobiba.com',
        defaultTtl: 600,
        credentialSet: true,
        createdAt: '2026-07-19T00:00:00.000Z',
        updatedAt: '2026-07-19T00:00:00.000Z'
      }],
      smtpCredential: null,
      apiTokens: [],
      inboundMailboxes: [],
      inboundMessageCount: 0,
      sendEventCount: 0
    }
  ],
  warnings: []
};

const runtimeConfig: RuntimeConfig = {
  appBaseUrl: 'https://mail.example.test',
  mailHostname: 'mail.example.test',
  sendingIp: '192.0.2.10',
  defaultSpfMechanisms: '',
  dmarcPolicy: 'none',
  dmarcRua: '',
  registrationRequiresApproval: false,
  sendRequiresVerified: true,
  engagementTrackingEnabled: true,
  listUnsubscribeMailto: '',
  listUnsubscribeUrl: '',
  listUnsubscribePostEnabled: false,
  feedbackIdEnabled: false,
  reportAbuseTo: '',
  csaComplaintsTo: '',
  bounceAddress: '',
  bounceEnvelopeEnabled: false
};

const appContext: AppContextValue = {
  user: users[0],
  config: runtimeConfig,
  refreshBootstrap: vi.fn(async () => undefined),
  logout: vi.fn(async () => undefined)
};
