import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { McpLogger, McpToolRequest } from '../tools/types.js';

process.env.JWT_SECRET ??= 'test-secret';
process.env.PLATFORM_SERVICE_URL ??= 'http://localhost:4003';
process.env.EXTRACTION_SERVICE_URL ??= 'http://localhost:4005';

vi.mock('../../lib/platform-client.js', () => ({
  aiBudgetsRecordSpend: vi.fn(),
  reviewsCreate: vi.fn(),
  supportCasesCreate: vi.fn(),
  runsCreate: vi.fn(),
  runsUpdate: vi.fn(),
  runStepsCreate: vi.fn(),
  runStepsUpdate: vi.fn(),
}));

vi.mock('../../lib/extraction-client.js', () => ({
  extractionRun: vi.fn(),
}));

vi.mock('../../lib/jarvis-client.js', () => ({
  jarvisMarketplaceGetListing: vi.fn(),
  jarvisMarketplaceCertify: vi.fn(),
  jarvisTeamsListMembers: vi.fn(),
  jarvisAgentsList: vi.fn(),
  jarvisMemoryCreate: vi.fn(),
}));

vi.mock('../../lib/lysnrai-client.js', () => ({
  lysnraiOrgGet: vi.fn(),
  lysnraiApiTokensList: vi.fn(),
  lysnraiSessionsList: vi.fn(),
  lysnraiTranscriptsList: vi.fn(),
  lysnraiTranscriptRunExtraction: vi.fn(),
}));

import {
  aiBudgetsRecordSpend,
  reviewsCreate,
  supportCasesCreate,
  runsCreate,
  runsUpdate,
  runStepsCreate,
  runStepsUpdate,
} from '../../lib/platform-client.js';
import { extractionRun } from '../../lib/extraction-client.js';
import { jarvisMarketplaceCertify, jarvisMarketplaceGetListing } from '../../lib/jarvis-client.js';
import {
  lysnraiApiTokensList,
  lysnraiOrgGet,
  lysnraiSessionsList,
  lysnraiTranscriptRunExtraction,
  lysnraiTranscriptsList,
} from '../../lib/lysnrai-client.js';

const log: McpLogger = {
  info: vi.fn(),
  warn: vi.fn(),
  error: vi.fn(),
  debug: vi.fn(),
};

function buildReq(id = 'req_1'): McpToolRequest {
  return {
    id,
    headers: { authorization: 'Bearer jwt_1' },
    log,
    jwtPayload: { sub: 'admin_1', role: 'admin', productId: 'lysnrai' },
  } as unknown as McpToolRequest;
}

beforeEach(() => {
  vi.clearAllMocks();
  vi.mocked(aiBudgetsRecordSpend).mockResolvedValue({} as never);
  vi.mocked(reviewsCreate).mockResolvedValue({} as never);
  vi.mocked(supportCasesCreate).mockResolvedValue({} as never);
  vi.mocked(runsCreate).mockResolvedValue({} as never);
  vi.mocked(runsUpdate).mockResolvedValue({} as never);
  vi.mocked(runStepsCreate).mockResolvedValue({} as never);
  vi.mocked(runStepsUpdate).mockResolvedValue({} as never);
});

describe('A2A governance integration', () => {
  it('records budget spend and creates support case for NL parser regressions', async () => {
    const { runNLParserEvalPipeline } = await import('./nl-parser-eval-pipeline.js');
    vi.mocked(extractionRun).mockResolvedValue({
      extractions: [],
      metadata: { modelId: 'gemini-2.5-flash', taskId: 'timer-parse' },
    });

    const report = await runNLParserEvalPipeline([], buildReq('req_eval'));

    expect(report.regressions.length).toBeGreaterThan(0);
    expect(aiBudgetsRecordSpend).toHaveBeenCalledOnce();
    expect(supportCasesCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        title: 'NL parser regression detected',
      }),
      expect.objectContaining({ productId: 'chronomind' })
    );
  });

  it('creates support case for marketplace certification needing human review', async () => {
    const { runMarketplaceCertPipeline } = await import('./marketplace-cert-pipeline.js');
    vi.mocked(jarvisMarketplaceGetListing).mockResolvedValue({
      id: 'listing_1',
      name: 'Coach',
      systemPrompt: 'safe prompt',
      coachingFramework: 'growth',
      category: 'productivity',
      tags: ['coach', 'habit'],
      voiceId: 'voice_1',
      description: 'Helpful description for the listing.',
    } as never);
    vi.mocked(extractionRun).mockResolvedValue({
      extractions: [
        {
          extraction_class: 'controversial',
          extraction_text: 'borderline copy',
        },
      ],
      metadata: { modelId: 'gemini-2.5-flash', taskId: 'triage' },
    });
    vi.mocked(jarvisMarketplaceCertify).mockResolvedValue({} as never);

    const result = await runMarketplaceCertPipeline('listing_1', {
      token: 'jwt_1',
      requestId: 'req_market',
    });

    expect(result.decision).toBe('pending_human_review');
    expect(aiBudgetsRecordSpend).toHaveBeenCalledOnce();
    expect(supportCasesCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        title: expect.stringContaining('Marketplace certification pending_human_review'),
      }),
      expect.objectContaining({ productId: 'jarvisjr' })
    );
  });

  it('records spend and opens support case when transcript extraction reports failures', async () => {
    const { runTranscriptExtractionPipeline } = await import('./transcript-extraction-pipeline.js');
    vi.mocked(lysnraiTranscriptsList).mockResolvedValue({
      transcripts: [
        { id: 't1', extractedAt: null },
        { id: 't2', extractedAt: null },
      ],
    } as never);
    vi.mocked(lysnraiTranscriptRunExtraction)
      .mockResolvedValueOnce({} as never)
      .mockRejectedValueOnce(new Error('boom'));

    const report = await runTranscriptExtractionPipeline(10, false, buildReq('req_tx'));

    expect(report.failed).toBe(1);
    expect(aiBudgetsRecordSpend).toHaveBeenCalledOnce();
    expect(supportCasesCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        title: 'Transcript extraction pipeline reported failures',
      }),
      expect.objectContaining({ productId: 'lysnrai' })
    );
  });

  it('creates an org-scoped review when org provisioning needs follow-up', async () => {
    const { runOrgProvisioningPipeline } = await import('./org-provisioning-pipeline.js');
    vi.mocked(lysnraiOrgGet).mockResolvedValue({ id: 'org_1', name: 'Acme' } as never);
    vi.mocked(lysnraiApiTokensList).mockResolvedValue({ tokens: [] } as never);
    vi.mocked(lysnraiSessionsList).mockResolvedValue({ total: 0 } as never);

    const report = await runOrgProvisioningPipeline('org_1', buildReq('req_org'));

    expect(report.onboardingStatus).toBe('new_org');
    expect(reviewsCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        orgId: 'org_1',
        category: 'org_onboarding',
        actionType: 'org_onboarding_followup',
      }),
      expect.objectContaining({ productId: 'lysnrai' })
    );
  });

  it('creates a support case when team provisioning is only partially successful', async () => {
    const { runTeamProvisioningPipeline } = await import('./team-provisioning-pipeline.js');
    const { jarvisTeamsListMembers, jarvisAgentsList, jarvisMemoryCreate } =
      await import('../../lib/jarvis-client.js');

    vi.mocked(jarvisTeamsListMembers).mockResolvedValue({
      members: [
        {
          userId: 'u1',
          teamId: 'team_1',
          role: 'member',
          status: 'invited',
          joinedAt: new Date().toISOString(),
        },
      ],
      total: 1,
    } as never);
    vi.mocked(jarvisAgentsList).mockResolvedValue({
      agents: [
        {
          id: 'agt_1',
          role: 'productivity_coach',
        },
      ],
      total: 1,
    } as never);
    vi.mocked(jarvisMemoryCreate).mockRejectedValue(new Error('memory down'));

    const report = await runTeamProvisioningPipeline('team_1', 48, buildReq('req_team'));

    expect(report.failed).toBe(1);
    expect(supportCasesCreate).toHaveBeenCalledWith(
      expect.objectContaining({
        title: 'Team provisioning follow-up for team_1',
      }),
      expect.objectContaining({ productId: 'jarvisjr' })
    );
  });
});
