import { beforeEach, describe, expect, it, vi } from 'vitest';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { YinianSkills } from '@/pages/YinianSkills';
import { useYinianStore } from '@/stores/yinian';
import { useYinianSkillsStore } from '@/stores/yinian-skills';
import { useSkillsStore } from '@/stores/skills';
import { useQuickTasksStore } from '@/stores/quick-tasks';
import i18n from '@/i18n';
import type { YinianConfigSnapshot, YinianLocalSkill } from '../../shared/yinian';

const toastSuccessMock = vi.fn();
const toastErrorMock = vi.fn();

vi.mock('sonner', () => ({
  toast: {
    success: (...args: unknown[]) => toastSuccessMock(...args),
    error: (...args: unknown[]) => toastErrorMock(...args),
  },
}));

const hotelHangzhou = {
  id: 'workspace_hangzhou_ops',
  name: '智念企业组织空间',
  city: '杭州',
  role: 'manager' as const,
  permissions: ['skills.sync'],
  ota: [],
};

const hotelShanghai = {
  id: 'workspace_shanghai_growth',
  name: '智念增长组织空间',
  city: '上海',
  role: 'viewer' as const,
  permissions: ['skills.read'],
  ota: [],
};

function createConfig(overrides: Partial<YinianConfigSnapshot> = {}): YinianConfigSnapshot {
  return {
    serverTime: 1,
    user: { id: 'user_1', name: '王管理员' },
    hotel: hotelHangzhou,
    hotels: [hotelHangzhou, hotelShanghai],
    entitlements: [],
    notificationChannels: [],
    featureFlags: {},
    uiPolicy: { defaultPage: 'today', showAdvancedSettings: false },
    ...overrides,
  };
}

function createLocalSkill(overrides: Partial<YinianLocalSkill>): YinianLocalSkill {
  return {
    skillId: 'daily-report',
    name: '日报生成助手',
    version: '1.0.0',
    enabled: true,
    installedAt: 1,
    lastSyncedAt: 2,
    status: 'installed',
    source: 'mock',
    ...overrides,
  };
}

function clickCapabilityTab(label: '服务下发' | '本地安装') {
  fireEvent.click(screen.getByRole('button', { name: new RegExp(`^${label}\\s+\\d+$`) }));
}

describe('YinianSkills page', () => {
  beforeEach(async () => {
    vi.clearAllMocks();
    await i18n.changeLanguage('zh');
    useYinianStore.setState({
      status: 'authenticated',
      session: {
        authenticated: true,
        user: { id: 'user_1', name: '王管理员' },
        hotels: [hotelHangzhou, hotelShanghai],
        currentHotelId: hotelHangzhou.id,
        accessTokenExpiresAt: 100,
      },
      config: createConfig(),
      error: null,
    });
    useYinianSkillsStore.setState({
      localSkills: [],
      lastSync: null,
      loading: false,
      error: null,
    });
    useSkillsStore.setState({
      skills: [],
      loading: false,
      error: null,
      fetchSkills: vi.fn().mockResolvedValue(undefined),
    });
    useQuickTasksStore.setState({ tasks: [] });
    vi.mocked(window.yinian.skills.getRegistry).mockReset();
    vi.mocked(window.yinian.skills.getRegistry).mockResolvedValue(undefined);
    vi.mocked(window.yinian.skills.sync).mockReset();
  });

  it('shows empty entitlement state', () => {
    render(<YinianSkills />);

    expect(screen.getByText('业务能力包')).toBeInTheDocument();
    clickCapabilityTab('服务下发');
    expect(screen.getByTestId('yinian-skills-empty-entitlements')).toHaveTextContent('当前组织空间尚未开通能力包');
  });

  it('maps entitlement and registry states for installed, update, disabled, and failed skills', () => {
    useYinianStore.setState({
      config: createConfig({
        entitlements: [
          {
            skillId: 'daily-report',
            name: '日报生成助手',
            version: '1.0.0',
            enabled: true,
            category: 'reporting',
            triggers: ['scheduled'],
          },
          {
            skillId: 'data-check',
            name: '数据检查助手',
            version: '1.2.0',
            enabled: true,
            category: 'ota-monitoring',
            triggers: ['manual'],
          },
          {
            skillId: 'customer-reply-helper',
            name: '客户回复助手',
            version: '0.9.0',
            enabled: false,
            category: 'guest-comm',
            triggers: ['manual'],
          },
          {
            skillId: 'ops-check',
            name: '流程检查',
            version: '0.1.0',
            enabled: true,
            category: 'ops-automation',
            triggers: [],
          },
        ],
      }),
    });
    useYinianSkillsStore.setState({
      localSkills: [
        createLocalSkill({ skillId: 'daily-report', name: '日报生成助手', version: '1.0.0', status: 'skipped' }),
        createLocalSkill({ skillId: 'data-check', name: '数据检查助手', version: '1.1.0', status: 'installed', source: 'nianxx', bundleSha256: 'sha256-demo' }),
        createLocalSkill({ skillId: 'ops-check', name: '流程检查', version: '0.1.0', status: 'failed', error: 'download failed' }),
      ],
    });

    render(<YinianSkills />);
    clickCapabilityTab('服务下发');

    expect(screen.getByTestId('yinian-skill-state-daily-report')).toHaveTextContent('已是最新');
    expect(screen.getByTestId('yinian-skill-state-data-check')).toHaveTextContent('有更新');
    expect(screen.getByTestId('yinian-skill-state-customer-reply-helper')).toHaveTextContent('已禁用');
    expect(screen.getByTestId('yinian-skill-state-ops-check')).toHaveTextContent('同步失败');
    fireEvent.click(screen.getByRole('button', { name: /流程检查/ }));
    expect(screen.getByText('download failed')).toBeInTheDocument();
    expect(screen.getAllByText('版本校验').length).toBeGreaterThan(0);
  });

  it('shows locally installed OpenClaw skills in a separate tab', () => {
    useSkillsStore.setState({
      skills: [
        {
          id: 'local-summary',
          slug: 'local-summary',
          name: '本地总结助手',
          description: '整理本地会话内容',
          enabled: true,
          version: '0.2.0',
          source: 'openclaw-managed',
          baseDir: '/tmp/openclaw/skills/local-summary',
        },
      ],
      loading: false,
      error: null,
      fetchSkills: vi.fn().mockResolvedValue(undefined),
    });

    render(<YinianSkills />);
    clickCapabilityTab('本地安装');

    expect(screen.getByText('本地总结助手')).toBeInTheDocument();
    expect(screen.getByText('整理本地会话内容')).toBeInTheDocument();
    fireEvent.click(screen.getByRole('button', { name: /本地总结助手/ }));
    expect(screen.getByText('/tmp/openclaw/skills/local-summary')).toBeInTheDocument();
  });

  it('hides OpenClaw built-in skills from local capability packs by default', () => {
    useSkillsStore.setState({
      skills: [
        {
          id: 'builtin-search',
          slug: 'builtin-search',
          name: 'OpenClaw 内置搜索',
          description: 'OpenClaw 自带能力',
          enabled: true,
          version: '1.0.0',
          isBundled: true,
          source: 'openclaw-bundled',
        },
        {
          id: 'extra-helper',
          slug: 'extra-helper',
          name: 'OpenClaw 扩展目录助手',
          description: 'OpenClaw 扩展目录能力',
          enabled: true,
          version: '1.0.0',
          source: 'openclaw-extra',
        },
        {
          id: 'local-summary',
          slug: 'local-summary',
          name: '本地总结助手',
          description: '整理本地会话内容',
          enabled: true,
          version: '0.2.0',
          source: 'openclaw-managed',
          baseDir: '/tmp/openclaw/skills/local-summary',
        },
      ],
      loading: false,
      error: null,
      fetchSkills: vi.fn().mockResolvedValue(undefined),
    });

    render(<YinianSkills />);
    clickCapabilityTab('本地安装');

    expect(screen.queryByText('OpenClaw 内置搜索')).not.toBeInTheDocument();
    expect(screen.queryByText('OpenClaw 扩展目录助手')).not.toBeInTheDocument();
    expect(screen.getByText('本地总结助手')).toBeInTheDocument();
  });

  it('shows empty registry warning when entitlements exist but no local skills are installed', () => {
    useYinianStore.setState({
      config: createConfig({
        entitlements: [
          {
            skillId: 'daily-report',
            name: '日报生成助手',
            version: '1.0.0',
            enabled: true,
            category: 'reporting',
            triggers: ['scheduled'],
          },
        ],
      }),
    });

    render(<YinianSkills />);
    clickCapabilityTab('服务下发');

    expect(screen.getByTestId('yinian-skill-state-daily-report')).toHaveTextContent('已开通未同步');
    expect(screen.getByTestId('yinian-skills-empty-registry')).toHaveTextContent('这台电脑还没有准备好能力包');
  });

  it('sync button stores result and shows success toast', async () => {
    useYinianStore.setState({
      config: createConfig({
        entitlements: [
          {
            skillId: 'daily-report',
            name: '日报生成助手',
            version: '1.0.0',
            enabled: true,
            category: 'reporting',
            triggers: ['scheduled'],
          },
        ],
      }),
    });
    vi.mocked(window.yinian.skills.sync).mockResolvedValueOnce({
      hotelId: hotelHangzhou.id,
      syncedAt: 10,
      skills: [createLocalSkill({ skillId: 'daily-report', name: '日报生成助手', version: '1.0.0', status: 'installed' })],
    });

    render(<YinianSkills />);
    const syncButton = screen.getByRole('button', { name: '同步能力包' });
    await waitFor(() => {
      expect(syncButton).not.toBeDisabled();
    });
    fireEvent.click(syncButton);

    await waitFor(() => {
      expect(window.yinian.skills.sync).toHaveBeenCalled();
      expect(toastSuccessMock).toHaveBeenCalledWith('能力包已同步');
    });
    expect(useYinianSkillsStore.getState().localSkills).toHaveLength(1);
  });

  it('loads registry for the current workspace when workspace changes', async () => {
    const { rerender } = render(<YinianSkills />);
    await waitFor(() => {
      expect(window.yinian.skills.getRegistry).toHaveBeenCalledWith(hotelHangzhou.id);
    });

    useYinianStore.setState({
      config: createConfig({
        hotel: hotelShanghai,
      }),
    });
    rerender(<YinianSkills />);

    await waitFor(() => {
      expect(window.yinian.skills.getRegistry).toHaveBeenCalledWith(hotelShanghai.id);
    });
  });
});
