import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { container } from 'tsyringe';
import { AITaskService } from '../../services/ai/ai-task.service';
import { OpenAIService } from '../../services/ai/openai.service';
import { LangChainService } from '../../services/ai/langchain.service';

/**
 * Request validation schemas
 */
const CreateTaskSchema = z.object({
  prompt: z.string().min(1).max(1000),
  projectId: z.string().optional(),
  context: z.object({
    currentTasks: z.array(z.string()).optional(),
    completedTasks: z.array(z.string()).optional(),
    projectDescription: z.string().optional(),
    userRole: z.string().optional(),
  }).optional(),
});

const UpdateContextSchema = z.object({
  feedback: z.string().min(1).max(5000),
});

const BreakdownTaskSchema = z.object({
  taskDescription: z.string().min(1).max(2000),
  context: z.string().optional(),
});

const GetSuggestionsSchema = z.object({
  projectDescription: z.string().min(1),
  completedTasks: z.array(z.string()),
  currentTasks: z.array(z.string()),
  goals: z.array(z.string()),
});

/**
 * Controller for AI-powered task management endpoints
 */
export class AIController {
  private aiTaskService: AITaskService;
  private openAIService: OpenAIService;
  private langChainService: LangChainService;

  constructor() {
    // Get services from DI container
    this.aiTaskService = container.resolve('AITaskService');
    this.openAIService = container.resolve('OpenAIService');
    this.langChainService = container.resolve('LangChainService');
  }

  /**
   * POST /api/ai/create-task
   * Create a task from natural language input
   */
  async createTask(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      // Validate request body
      const validatedData = CreateTaskSchema.parse(req.body);

      // Create task using AI service
      const task = await this.aiTaskService.createTaskFromNaturalLanguage({
        prompt: validatedData.prompt,
        projectId: validatedData.projectId,
        context: validatedData.context,
      });

      res.status(201).json({
        success: true,
        data: task,
        message: 'Task created successfully from natural language',
      });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: 'Validation error',
          details: error.issues,
        });
        return;
      }

      // Check for rate limiting error
      if (error instanceof Error && error.message.includes('Rate limit exceeded')) {
        res.status(429).json({
          success: false,
          error: 'Rate limit exceeded',
          message: 'Too many requests. Please try again later.',
        });
        return;
      }

      next(error);
    }
  }

  /**
   * PUT /api/ai/update-context/:taskId
   * Update AI context for a task with user feedback
   */
  async updateTaskContext(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { taskId } = req.params;
      
      // Validate request body
      const validatedData = UpdateContextSchema.parse(req.body);

      // Update context
      await this.aiTaskService.updateTaskContext(taskId, validatedData.feedback);

      res.status(200).json({
        success: true,
        message: 'Task context updated successfully',
      });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: 'Validation error',
          details: error.issues,
        });
        return;
      }

      next(error);
    }
  }

  /**
   * GET /api/ai/suggestions/:projectId
   * Get AI-powered task suggestions for a project
   */
  async getTaskSuggestions(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { projectId } = req.params;
      
      // Validate query parameters
      const validatedData = GetSuggestionsSchema.parse({
        projectDescription: req.query.projectDescription,
        completedTasks: req.query.completedTasks 
          ? (req.query.completedTasks as string).split(',') 
          : [],
        currentTasks: req.query.currentTasks 
          ? (req.query.currentTasks as string).split(',') 
          : [],
        goals: req.query.goals 
          ? (req.query.goals as string).split(',') 
          : [],
      });

      // Get suggestions
      const suggestions = await this.aiTaskService.getTaskSuggestions(
        projectId,
        validatedData,
      );

      res.status(200).json({
        success: true,
        data: suggestions,
        projectId,
      });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: 'Validation error',
          details: error.issues,
        });
        return;
      }

      // Check for rate limiting error
      if (error instanceof Error && error.message.includes('Rate limit exceeded')) {
        res.status(429).json({
          success: false,
          error: 'Rate limit exceeded',
          message: 'Too many requests. Please try again later.',
        });
        return;
      }

      next(error);
    }
  }

  /**
   * POST /api/ai/breakdown/:taskId
   * Break down a task into subtasks using AI
   */
  async breakdownTask(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { taskId } = req.params;
      
      // Validate request body
      const validatedData = BreakdownTaskSchema.parse(req.body);

      // Break down the task
      const breakdown = await this.aiTaskService.breakdownTask(
        taskId,
        validatedData.taskDescription,
        validatedData.context,
      );

      res.status(200).json({
        success: true,
        data: breakdown,
        taskId,
      });
    } catch (error) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: 'Validation error',
          details: error.issues,
        });
        return;
      }

      // Check for rate limiting error
      if (error instanceof Error && error.message.includes('Rate limit exceeded')) {
        res.status(429).json({
          success: false,
          error: 'Rate limit exceeded',
          message: 'Too many requests. Please try again later.',
        });
        return;
      }

      next(error);
    }
  }

  /**
   * GET /api/ai/health
   * Check health status of AI services
   */
  async getHealthStatus(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const health = await this.aiTaskService.getHealthStatus();

      const overallHealth = health.openai && health.langchain;

      res.status(overallHealth ? 200 : 503).json({
        success: true,
        healthy: overallHealth,
        services: health,
        timestamp: new Date().toISOString(),
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * GET /api/ai/usage
   * Get usage statistics for AI services
   */
  async getUsageStats(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const stats = await this.aiTaskService.getUsageStats();

      res.status(200).json({
        success: true,
        data: stats,
        timestamp: new Date().toISOString(),
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /api/ai/warm-cache
   * Warm cache with common queries for a project
   */
  async warmCache(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const { projectId } = req.body;

      if (!projectId) {
        res.status(400).json({
          success: false,
          error: 'Project ID is required',
        });
        return;
      }

      // Warm cache in background
      this.aiTaskService.warmCache(projectId).catch(error => {
        console.error('Cache warming failed:', error);
      });

      res.status(202).json({
        success: true,
        message: 'Cache warming initiated',
        projectId,
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * POST /api/ai/test-connection
   * Test connection to AI services
   */
  async testConnection(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const [openaiTest, langchainTest] = await Promise.all([
        this.openAIService.testConnection(),
        this.langChainService.testConnection(),
      ]);

      res.status(200).json({
        success: true,
        connections: {
          openai: openaiTest,
          langchain: langchainTest,
        },
        message: openaiTest && langchainTest 
          ? 'All AI services are connected' 
          : 'Some AI services are not available',
      });
    } catch (error) {
      next(error);
    }
  }
}

// Export singleton instance
export const aiController = new AIController();