import { describe, it, expect, beforeEach, vi } from 'vitest';
import { BusinessAnalyzer } from '../analyzer.js';
import { BusinessPlan, MarketAnalysis, CompetitorAnalysis } from '../types.js';
import { ConfigManager } from '../../../config/config-manager.js';

// Mock ConfigManager
vi.mock('../../../config/config-manager.js');

// Mock fs
vi.mock('fs', () => ({
  promises: {
    readFile: vi.fn().mockRejectedValue(new Error('File not found')),
    writeFile: vi.fn().mockResolvedValue(undefined),
    mkdir: vi.fn().mockResolvedValue(undefined)
  }
}));

describe('BusinessAnalyzer', () => {
  let businessAnalyzer: BusinessAnalyzer;
  let mockConfigManager: vi.Mocked<ConfigManager>;
  
  it('should create BusinessAnalyzer instance', () => {
    const config = {} as any;
    const analyzer = new BusinessAnalyzer(config);
    expect(analyzer).toBeInstanceOf(BusinessAnalyzer);
  });

  beforeEach(async () => {
    mockConfigManager = {
      getStorageManager: vi.fn().mockReturnValue({
        getStorageLocation: vi.fn().mockResolvedValue({
          data: '/tmp/test-data'
        })
      })
    } as any;
    
    businessAnalyzer = new BusinessAnalyzer(mockConfigManager);
    await businessAnalyzer.init();
  });

  describe('generateBusinessPlan', () => {
    it('should generate business plan with lean canvas template', async () => {
      const options = {
        businessIdea: 'AI-powered project management tool',
        targetMarket: 'Software development teams',
        businessModel: 'SaaS subscription',
        timeline: 12,
        template: 'lean_canvas' as const,
      };

      const businessPlan = await businessAnalyzer.generateBusinessPlan(options);

      expect(businessPlan.id).toMatch(/^plan-[a-z0-9-]+$/);
      expect(businessPlan.businessIdea).toBe(options.businessIdea);
      expect(businessPlan.targetMarket).toBe(options.targetMarket);
      expect(businessPlan.businessModel).toBe(options.businessModel);
      expect(businessPlan.timeline).toBe(options.timeline);
      expect(businessPlan.template).toBe('lean_canvas');
      expect(businessPlan.sections).toBeDefined();
      expect(businessPlan.sections.length).toBeGreaterThan(0);
    });

    it('should generate business plan with traditional template', async () => {
      const options = {
        businessIdea: 'E-commerce platform',
        targetMarket: 'Small businesses',
        businessModel: 'Commission-based',
        timeline: 24,
        template: 'traditional' as const,
      };

      const businessPlan = await businessAnalyzer.generateBusinessPlan(options);

      expect(businessPlan.template).toBe('traditional');
      expect(businessPlan.sections).toBeDefined();
      expect(businessPlan.createdAt).toBeDefined();
      expect(businessPlan.updatedAt).toBeDefined();
    });

    it('should include financial projections', async () => {
      const options = {
        businessIdea: 'Mobile app',
        targetMarket: 'Consumers',
        businessModel: 'Freemium',
        timeline: 18,
        includeFinancials: true,
        template: 'traditional',
      };

      const businessPlan = await businessAnalyzer.generateBusinessPlan(options);

      expect(businessPlan.financials).toBeDefined();
      expect(businessPlan.financials?.revenue).toBeDefined();
      expect(businessPlan.financials?.expenses).toBeDefined();
      expect(businessPlan.financials?.projections).toBeDefined();
    });
  });

  describe('analyzeMarket', () => {
    it('should analyze market for given industry and target market', async () => {
      const options = {
        industry: 'Software Development',
        targetMarket: 'Small to medium businesses',
        geographicScope: 'North America',
      };

      const marketAnalysis = await businessAnalyzer.analyzeMarket(options);

      expect(marketAnalysis.id).toMatch(/^market-[a-z0-9-]+$/);
      expect(marketAnalysis.industry).toBe(options.industry);
      expect(marketAnalysis.targetMarket).toBe(options.targetMarket);
      expect(marketAnalysis.geographicScope).toBe(options.geographicScope);
      expect(marketAnalysis.marketSize).toBeDefined();
      expect(marketAnalysis.trends).toBeDefined();
      expect(marketAnalysis.trends.length).toBeGreaterThan(0);
      expect(marketAnalysis.opportunities).toBeDefined();
      expect(marketAnalysis.challenges).toBeDefined();
    });

    it('should include demographic analysis when requested', async () => {
      const options = {
        industry: 'E-commerce',
        targetMarket: 'Millennials',
        geographicScope: 'United States',
        includeDemographics: true,
      };

      const marketAnalysis = await businessAnalyzer.analyzeMarket(options);

      expect(marketAnalysis.demographics).toBeDefined();
      expect(marketAnalysis.demographics?.ageRange).toBeDefined();
      expect(marketAnalysis.demographics?.income).toBeDefined();
      expect(marketAnalysis.demographics?.behavior).toBeDefined();
    });
  });

  describe('analyzeCompetitors', () => {
    it('should analyze competitors in the industry', async () => {
      const options = {
        businessIdea: 'AI-powered project management tool',
        industry: 'Project Management Software',
        competitors: ['Asana', 'Jira', 'Trello'],
        analysisDepth: 'detailed',
        includeStrengthWeakness: true,
      };

      const competitorAnalysis = await businessAnalyzer.analyzeCompetitors(options);

      expect(competitorAnalysis).toBeDefined();
      expect(competitorAnalysis.industry).toBe(options.industry);
      expect(competitorAnalysis.competitors).toBeDefined();
      expect(competitorAnalysis.competitors.length).toBeGreaterThan(0);
      
      const firstCompetitor = competitorAnalysis.competitors[0];
      expect(firstCompetitor.name).toBeDefined();
      expect(firstCompetitor.marketShare).toBeDefined();
      expect(firstCompetitor.strengths).toBeDefined();
      expect(firstCompetitor.weaknesses).toBeDefined();
      expect(firstCompetitor.pricingModel).toBeDefined();
    });

    it('should include competitive positioning', async () => {
      const options = {
        businessIdea: 'Simple CRM for freelancers',
        industry: 'CRM Software',
        competitors: ['Salesforce', 'HubSpot', 'Pipedrive'],
        analysisDepth: 'comprehensive',
        includeStrengthWeakness: true,
      };

      const competitorAnalysis = await businessAnalyzer.analyzeCompetitors(options);

      expect(competitorAnalysis.positioning).toBeDefined();
      expect(competitorAnalysis.positioning?.marketGaps).toBeDefined();
      expect(competitorAnalysis.positioning?.differentiationOpportunities).toBeDefined();
      expect(competitorAnalysis.positioning?.competitiveAdvantages).toBeDefined();
    });
  });

  describe('generatePitchDeck', () => {
    it('should generate pitch deck with standard slides', async () => {
      const options = {
        businessIdea: 'AI-powered project management',
        problemStatement: 'Teams struggle with project complexity',
        solution: 'AI assistant that simplifies project management',
        targetMarket: 'Software development teams',
        businessModel: 'SaaS subscription',
        competitiveAdvantage: 'AI-driven insights',
        fundingAsk: '$2M seed round',
        template: 'investor',
      };

      const pitchDeck = await businessAnalyzer.generatePitchDeck(options);

      expect(pitchDeck).toBeDefined();
      expect(pitchDeck.businessIdea).toBe(options.businessIdea);
      expect(pitchDeck.template).toBe(options.template);
      expect(pitchDeck.markdown).toBeDefined();
      expect(pitchDeck.keyMessages).toBeDefined();
      expect(pitchDeck.presentationTips).toBeDefined();
    });

    it('should customize slides for different audiences', async () => {
      const optionsForPartners = {
        businessIdea: 'B2B marketplace platform',
        problemStatement: 'Suppliers struggle to find buyers',
        solution: 'Digital marketplace connecting suppliers and buyers',
        targetMarket: 'Manufacturing industry',
        businessModel: 'Transaction fees',
        competitiveAdvantage: 'Industry-specific features',
        template: 'partner',
      };

      const pitchDeck = await businessAnalyzer.generatePitchDeck(optionsForPartners);

      expect(pitchDeck.template).toBe('partner');
      expect(pitchDeck.markdown).toBeDefined();
    });
  });

  describe('assessStartup', () => {
    it('should assess startup maturity across all dimensions', async () => {
      const options = {
        businessPlanId: 'plan-789',
        currentStage: 'mvp',
        teamSize: 5,
        monthsInDevelopment: 8,
        hasCustomers: true,
        monthlyRevenue: 5000,
      };

      const assessment = await businessAnalyzer.assessStartup(options);

      expect(assessment.id).toMatch(/^assessment-[a-f0-9-]+$/);
      expect(assessment.businessPlanId).toBe(options.businessPlanId);
      expect(assessment.overallScore).toBeGreaterThan(0);
      expect(assessment.overallScore).toBeLessThanOrEqual(100);
      expect(assessment.maturityLevel).toBeDefined();
      expect(assessment.dimensions).toBeDefined();
      
      // Check all key dimensions are assessed
      expect(assessment.dimensions.product).toBeDefined();
      expect(assessment.dimensions.market).toBeDefined();
      expect(assessment.dimensions.team).toBeDefined();
      expect(assessment.dimensions.financial).toBeDefined();
      expect(assessment.dimensions.operations).toBeDefined();
    });

    it('should provide recommendations for improvement', async () => {
      const options = {
        businessPlanId: 'plan-101',
        currentStage: 'idea',
        teamSize: 1,
        monthsInDevelopment: 1,
        hasCustomers: false,
        monthlyRevenue: 0,
      };

      const assessment = await businessAnalyzer.assessStartup(options);

      expect(assessment.recommendations).toBeDefined();
      expect(assessment.recommendations.length).toBeGreaterThan(0);
      expect(assessment.nextSteps).toBeDefined();
      expect(assessment.nextSteps.length).toBeGreaterThan(0);
    });
  });

  describe('planFundingStrategy', () => {
    it('should plan funding strategy based on business needs', async () => {
      const options = {
        businessPlanId: 'plan-202',
        fundingGoal: 500000,
        currentStage: 'mvp',
        useOfFunds: ['product-development', 'marketing', 'hiring'],
        timeline: 6,
      };

      const fundingStrategy = await businessAnalyzer.planFundingStrategy(options);

      expect(fundingStrategy.id).toMatch(/^funding-[a-f0-9-]+$/);
      expect(fundingStrategy.businessPlanId).toBe(options.businessPlanId);
      expect(fundingStrategy.fundingGoal).toBe(options.fundingGoal);
      expect(fundingStrategy.recommendedSources).toBeDefined();
      expect(fundingStrategy.recommendedSources.length).toBeGreaterThan(0);
      expect(fundingStrategy.timeline).toBeDefined();
      expect(fundingStrategy.milestones).toBeDefined();
    });

    it('should recommend appropriate funding sources for stage', async () => {
      const seedStageOptions = {
        businessPlanId: 'plan-303',
        fundingGoal: 100000,
        currentStage: 'idea',
        timeline: 3,
      };

      const seedStrategy = await businessAnalyzer.planFundingStrategy(seedStageOptions);

      expect(seedStrategy.recommendedSources).toContain('angel-investors');
      expect(seedStrategy.recommendedSources).toContain('grants');

      const seriesAOptions = {
        businessPlanId: 'plan-404',
        fundingGoal: 2000000,
        currentStage: 'growth',
        timeline: 12,
      };

      const seriesAStrategy = await businessAnalyzer.planFundingStrategy(seriesAOptions);

      expect(seriesAStrategy.recommendedSources).toContain('venture-capital');
    });
  });

  describe('error handling', () => {
    it('should handle invalid business plan parameters', async () => {
      const invalidOptions = {
        businessIdea: '', // Empty business idea
        targetMarket: 'Invalid market',
        businessModel: 'Unknown model',
        timeline: -1, // Invalid timeline
      };

      await expect(
        businessAnalyzer.generateBusinessPlan(invalidOptions)
      ).rejects.toThrow();
    });

    it('should handle missing required parameters', async () => {
      const incompleteOptions = {
        // Missing required fields
      };

      await expect(
        businessAnalyzer.analyzeMarket(incompleteOptions as any)
      ).rejects.toThrow();
    });
  });
});