/**
 * Test Data Manager
 * Handles creation and cleanup of test data for E2E tests
 */

import { APIRequestContext, request } from '@playwright/test';

export interface TestUser {
  id?: string;
  email: string;
  password: string;
  fullName: string;
}

export interface TestScenario {
  id?: string;
  name: string;
  description?: string;
  region: string;
  tags: string[];
  status?: string;
}

export interface TestReport {
  id?: string;
  scenarioId: string;
  format: 'pdf' | 'csv';
  status?: string;
}

export interface TestScheduledReport {
  id?: string;
  scenarioId: string;
  name: string;
  frequency: 'daily' | 'weekly' | 'monthly';
  format: 'pdf' | 'csv';
}

export interface TestReportTemplate {
  id?: string;
  name: string;
  sections: string[];
}

export class TestDataManager {
  private apiContext: APIRequestContext | null = null;
  private baseUrl: string;
  private authToken: string | null = null;
  
  // Track created entities for cleanup
  private users: string[] = [];
  private scenarios: string[] = [];
  private reports: string[] = [];
  private scheduledReports: string[] = [];
  private apiKeys: string[] = [];

  constructor(baseUrl: string = 'http://localhost:8000') {
    this.baseUrl = baseUrl;
  }

  async init() {
    this.apiContext = await request.newContext({
      baseURL: this.baseUrl,
    });
  }

  async cleanup() {
    // Clean up in reverse order of dependencies
    await this.cleanupReports();
    await this.cleanupScheduledReports();
    await this.cleanupScenarios();
    await this.cleanupApiKeys();
    await this.cleanupUsers();
    
    await this.apiContext?.dispose();
  }

  // ==================== USER MANAGEMENT ====================
  
  async createTestUser(userData?: Partial<TestUser>): Promise<TestUser> {
    if (!this.apiContext) await this.init();
    
    const user: TestUser = {
      email: userData?.email || `test_${Date.now()}_${Math.random().toString(36).substring(7)}@example.com`,
      password: userData?.password || 'TestPassword123!',
      fullName: userData?.fullName || 'Test User',
    };

    const response = await this.apiContext!.post('/api/v1/auth/register', {
      data: {
        email: user.email,
        password: user.password,
        full_name: user.fullName,
      },
    });

    if (response.ok()) {
      const data = await response.json();
      user.id = data.id;
      this.users.push(user.id!);
      
      // Login to get token
      await this.login(user.email, user.password);
    }

    return user;
  }

  async login(email: string, password: string): Promise<string | null> {
    if (!this.apiContext) await this.init();
    
    const response = await this.apiContext!.post('/api/v1/auth/login', {
      data: {
        username: email,
        password: password,
      },
    });

    if (response.ok()) {
      const data = await response.json();
      this.authToken = data.access_token;
      return this.authToken;
    }
    
    return null;
  }

  private async cleanupUsers() {
    // Users are cleaned up at database level or left for reference
    // In production, you might want to actually delete them
    this.users = [];
  }

  // ==================== SCENARIO MANAGEMENT ====================
  
  async createScenario(scenarioData: TestScenario): Promise<TestScenario> {
    if (!this.apiContext) await this.init();
    
    const response = await this.apiContext!.post('/api/v1/scenarios', {
      data: {
        name: scenarioData.name,
        description: scenarioData.description || '',
        region: scenarioData.region,
        tags: scenarioData.tags,
      },
      headers: this.getAuthHeaders(),
    });

    if (response.ok()) {
      const data = await response.json();
      scenarioData.id = data.id;
      this.scenarios.push(data.id);
    }

    return scenarioData;
  }

  async addScenarioLogs(scenarioId: string, count: number = 10) {
    if (!this.apiContext) await this.init();
    
    const logs = Array.from({ length: count }, (_, i) => ({
      message: `Test log entry ${i + 1}`,
      source: 'e2e-test',
      level: ['INFO', 'WARN', 'ERROR'][Math.floor(Math.random() * 3)],
      timestamp: new Date().toISOString(),
    }));

    for (const log of logs) {
      await this.apiContext!.post('/ingest', {
        data: log,
        headers: {
          ...this.getAuthHeaders(),
          'X-Scenario-ID': scenarioId,
        },
      });
    }
  }

  async addScenarioLogWithPII(scenarioId: string) {
    if (!this.apiContext) await this.init();
    
    await this.apiContext!.post('/ingest', {
      data: {
        message: 'Contact us at test@example.com or call +1-555-123-4567',
        source: 'e2e-test',
        level: 'INFO',
      },
      headers: {
        ...this.getAuthHeaders(),
        'X-Scenario-ID': scenarioId,
      },
    });
  }

  async addScenarioMetrics(scenarioId: string, metrics: Record<string, number>) {
    if (!this.apiContext) await this.init();
    
    // Implementation depends on your metrics API
    await this.apiContext!.post(`/api/v1/scenarios/${scenarioId}/metrics`, {
      data: metrics,
      headers: this.getAuthHeaders(),
    });
  }

  private async cleanupScenarios() {
    if (!this.apiContext) return;
    
    for (const scenarioId of this.scenarios) {
      await this.apiContext.delete(`/api/v1/scenarios/${scenarioId}`, {
        headers: this.getAuthHeaders(),
        failOnStatusCode: false,
      });
    }
    this.scenarios = [];
  }

  // ==================== REPORT MANAGEMENT ====================
  
  async createReport(scenarioId: string, format: 'pdf' | 'csv'): Promise<TestReport> {
    if (!this.apiContext) await this.init();
    
    const response = await this.apiContext!.post(`/api/v1/scenarios/${scenarioId}/reports`, {
      data: {
        format,
        include_logs: true,
      },
      headers: this.getAuthHeaders(),
    });

    const report: TestReport = {
      id: response.ok() ? (await response.json()).id : undefined,
      scenarioId,
      format,
      status: 'pending',
    };

    if (report.id) {
      this.reports.push(report.id);
    }

    return report;
  }

  async createScheduledReport(scenarioId: string, scheduleData: Partial<TestScheduledReport>): Promise<TestScheduledReport> {
    if (!this.apiContext) await this.init();
    
    const schedule: TestScheduledReport = {
      id: undefined,
      scenarioId,
      name: scheduleData.name || 'Test Schedule',
      frequency: scheduleData.frequency || 'daily',
      format: scheduleData.format || 'pdf',
    };

    const response = await this.apiContext!.post(`/api/v1/scenarios/${scenarioId}/reports/schedule`, {
      data: schedule,
      headers: this.getAuthHeaders(),
    });

    if (response.ok()) {
      const data = await response.json();
      schedule.id = data.id;
      this.scheduledReports.push(data.id);
    }

    return schedule;
  }

  async createReportTemplate(templateData: Partial<TestReportTemplate>): Promise<TestReportTemplate> {
    if (!this.apiContext) await this.init();
    
    const template: TestReportTemplate = {
      id: undefined,
      name: templateData.name || 'Test Template',
      sections: templateData.sections || ['summary', 'charts'],
    };

    const response = await this.apiContext!.post('/api/v1/reports/templates', {
      data: template,
      headers: this.getAuthHeaders(),
    });

    if (response.ok()) {
      const data = await response.json();
      template.id = data.id;
    }

    return template;
  }

  private async cleanupReports() {
    if (!this.apiContext) return;
    
    for (const reportId of this.reports) {
      await this.apiContext.delete(`/api/v1/reports/${reportId}`, {
        headers: this.getAuthHeaders(),
        failOnStatusCode: false,
      });
    }
    this.reports = [];
  }

  private async cleanupScheduledReports() {
    if (!this.apiContext) return;
    
    for (const scheduleId of this.scheduledReports) {
      await this.apiContext.delete(`/api/v1/reports/schedule/${scheduleId}`, {
        headers: this.getAuthHeaders(),
        failOnStatusCode: false,
      });
    }
    this.scheduledReports = [];
  }

  // ==================== API KEY MANAGEMENT ====================
  
  async createApiKey(name: string, scopes: string[] = ['read']): Promise<string | null> {
    if (!this.apiContext) await this.init();
    
    const response = await this.apiContext!.post('/api/v1/api-keys', {
      data: {
        name,
        scopes,
      },
      headers: this.getAuthHeaders(),
    });

    if (response.ok()) {
      const data = await response.json();
      this.apiKeys.push(data.id);
      return data.key;
    }
    
    return null;
  }

  private async cleanupApiKeys() {
    if (!this.apiContext) return;
    
    for (const keyId of this.apiKeys) {
      await this.apiContext.delete(`/api/v1/api-keys/${keyId}`, {
        headers: this.getAuthHeaders(),
        failOnStatusCode: false,
      });
    }
    this.apiKeys = [];
  }

  // ==================== HELPERS ====================
  
  private getAuthHeaders(): Record<string, string> {
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
    };
    
    if (this.authToken) {
      headers['Authorization'] = `Bearer ${this.authToken}`;
    }
    
    return headers;
  }
}
