import { Request, Response } from 'express';
import { stateMachineService } from '../../workflow/stateMachine';
import { webhookService } from '../../workflow/webhookService';
import { auditLogger } from '../../workflow/auditLogger';
import { jobQueueService, JobType } from '../../workflow/jobQueue';
import { gitEventHandler } from '../../workflow/gitEventHandler';

/**
 * Workflow Controller
 * Handles all workflow-related HTTP requests
 */
export class WorkflowController {
  /**
   * State Machine Endpoints
   */

  async getTaskState(req: Request, res: Response): Promise<void> {
    try {
      const { taskId } = req.params;
      const state = await stateMachineService.getCurrentState(taskId);
      
      res.json({
        success: true,
        data: {
          taskId,
          currentState: state.value,
          context: state.context,
          history: state.history
        }
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async getAvailableTransitions(req: Request, res: Response): Promise<void> {
    try {
      const { taskId } = req.params;
      const transitions = await stateMachineService.getAvailableTransitions(taskId);
      
      res.json({
        success: true,
        data: {
          taskId,
          availableTransitions: transitions
        }
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async executeTransition(req: Request, res: Response): Promise<void> {
    try {
      const { taskId, event, metadata, userId, reason } = req.body;
      
      const newState = await stateMachineService.transition(taskId, {
        type: event,
        ...metadata,
        userId,
        reason
      } as any);
      
      // Log the transition
      await auditLogger.logWorkflowTransition(
        taskId,
        String(newState.history?.value || 'unknown'),
        String(newState.value),
        event,
        { userId, reason, ...metadata }
      );
      
      res.json({
        success: true,
        data: {
          taskId,
          previousState: newState.history?.value,
          currentState: newState.value,
          context: newState.context
        }
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async validateTransition(req: Request, res: Response): Promise<void> {
    try {
      const { taskId, event } = req.body;
      const isValid = await stateMachineService.canTransition(taskId, { type: event } as any);
      
      res.json({
        success: true,
        data: {
          taskId,
          event,
          isValid
        }
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Webhook Endpoints
   */

  async getWebhooks(req: Request, res: Response): Promise<void> {
    try {
      const { active, event } = req.query;
      const filter: any = {};
      
      if (active !== undefined) {
        filter.active = active === 'true';
      }
      if (event) {
        filter.event = String(event);
      }
      
      const webhooks = await webhookService.getWebhooks(filter);
      
      res.json({
        success: true,
        data: webhooks
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async registerWebhook(req: Request, res: Response): Promise<void> {
    try {
      const webhook = await webhookService.registerWebhook(req.body);
      
      res.status(201).json({
        success: true,
        data: webhook
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async updateWebhook(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const webhook = await webhookService.updateWebhook(id, req.body);
      
      res.json({
        success: true,
        data: webhook
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async deleteWebhook(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      await webhookService.deleteWebhook(id);
      
      res.json({
        success: true,
        message: 'Webhook deleted successfully'
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async testWebhook(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const result = await webhookService.testWebhook(id);
      
      res.json({
        success: true,
        data: result
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async getWebhookDeliveries(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const { limit } = req.query;
      
      const deliveries = await webhookService.getDeliveryHistory(
        id,
        limit ? parseInt(String(limit)) : 100
      );
      
      res.json({
        success: true,
        data: deliveries
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Audit Log Endpoints
   */

  async queryAuditLogs(req: Request, res: Response): Promise<void> {
    try {
      const query = req.query;
      const options: any = {};
      
      // Parse query parameters
      if (query.entityType) options.entityType = String(query.entityType);
      if (query.entityId) options.entityId = String(query.entityId);
      if (query.actorId) options.actorId = String(query.actorId);
      if (query.action) options.action = String(query.action);
      if (query.severity) options.severity = String(query.severity);
      if (query.startDate) options.startDate = new Date(String(query.startDate));
      if (query.endDate) options.endDate = new Date(String(query.endDate));
      if (query.tags) options.tags = Array.isArray(query.tags) ? query.tags : [query.tags];
      if (query.limit) options.limit = parseInt(String(query.limit));
      if (query.offset) options.offset = parseInt(String(query.offset));
      if (query.sort) options.sort = String(query.sort);
      
      const logs = await auditLogger.query(options);
      
      res.json({
        success: true,
        data: logs
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async getAuditStatistics(req: Request, res: Response): Promise<void> {
    try {
      const { startDate, endDate } = req.query;
      
      const statistics = await auditLogger.getStatistics(
        startDate ? new Date(String(startDate)) : undefined,
        endDate ? new Date(String(endDate)) : undefined
      );
      
      res.json({
        success: true,
        data: statistics
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async getAuditTimeline(req: Request, res: Response): Promise<void> {
    try {
      const { entityId } = req.params;
      const { entityType } = req.query;
      
      const timeline = await auditLogger.getTimeline(
        entityId,
        entityType ? String(entityType) : undefined
      );
      
      res.json({
        success: true,
        data: timeline
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async exportAuditLogs(req: Request, res: Response): Promise<void> {
    try {
      const { format, ...queryOptions } = req.query;
      
      const exportData = await auditLogger.exportLogs(
        queryOptions as any,
        format as 'json' | 'csv'
      );
      
      // Set appropriate headers
      const contentType = format === 'csv' 
        ? 'text/csv' 
        : 'application/json';
      const filename = `audit-logs-${Date.now()}.${format || 'json'}`;
      
      res.setHeader('Content-Type', contentType);
      res.setHeader('Content-Disposition', `attachment; filename="${filename}"`);
      
      res.send(exportData);
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Job Queue Endpoints
   */

  async addJob(req: Request, res: Response): Promise<void> {
    try {
      const { queue, type, taskId, payload, metadata, priority } = req.body;
      
      const job = await jobQueueService.addJob(
        queue || 'workflow',
        {
          type: type as JobType,
          taskId,
          payload,
          metadata
        },
        { priority }
      );
      
      res.status(201).json({
        success: true,
        data: {
          jobId: job.id,
          queue: queue || 'workflow',
          status: await job.getState()
        }
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async scheduleJob(req: Request, res: Response): Promise<void> {
    try {
      const { queue, type, taskId, payload, metadata, delay, scheduleAt } = req.body;
      
      const delayMs = scheduleAt 
        ? new Date(scheduleAt).getTime() - Date.now()
        : delay;
      
      const job = await jobQueueService.scheduleJob(
        queue || 'scheduled',
        {
          type: type as JobType,
          taskId,
          payload,
          metadata
        },
        delayMs
      );
      
      res.status(201).json({
        success: true,
        data: {
          jobId: job.id,
          queue: queue || 'scheduled',
          scheduledFor: new Date(Date.now() + delayMs).toISOString()
        }
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async addRecurringJob(req: Request, res: Response): Promise<void> {
    try {
      const { queue, type, taskId, payload, metadata, cron } = req.body;
      
      const job = await jobQueueService.addRecurringJob(
        queue || 'scheduled',
        {
          type: type as JobType,
          taskId,
          payload,
          metadata
        },
        cron
      );
      
      res.status(201).json({
        success: true,
        data: {
          jobId: job.id,
          queue: queue || 'scheduled',
          cronExpression: cron
        }
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async getQueueStatistics(req: Request, res: Response): Promise<void> {
    try {
      const { name } = req.params;
      const statistics = await jobQueueService.getQueueStatistics(name);
      
      res.json({
        success: true,
        data: statistics
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async pauseQueue(req: Request, res: Response): Promise<void> {
    try {
      const { name } = req.params;
      await jobQueueService.pauseQueue(name);
      
      res.json({
        success: true,
        message: `Queue ${name} paused successfully`
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async resumeQueue(req: Request, res: Response): Promise<void> {
    try {
      const { name } = req.params;
      await jobQueueService.resumeQueue(name);
      
      res.json({
        success: true,
        message: `Queue ${name} resumed successfully`
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async clearQueue(req: Request, res: Response): Promise<void> {
    try {
      const { name } = req.params;
      await jobQueueService.clearQueue(name);
      
      res.json({
        success: true,
        message: `Queue ${name} cleared successfully`
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  /**
   * Git Integration Endpoints
   */

  async createTaskBranch(req: Request, res: Response): Promise<void> {
    try {
      const { taskId, taskTitle } = req.body;
      const branchName = await gitEventHandler.createTaskBranch(taskId, taskTitle);
      
      res.status(201).json({
        success: true,
        data: {
          taskId,
          branchName
        }
      });
    } catch (error: any) {
      res.status(400).json({
        success: false,
        error: error.message
      });
    }
  }

  async getTaskGitInfo(req: Request, res: Response): Promise<void> {
    try {
      const { taskId } = req.params;
      const gitInfo = await gitEventHandler.getTaskGitInfo(taskId);
      
      if (!gitInfo) {
        res.status(404).json({
          success: false,
          error: 'No Git information found for this task'
        });
        return;
      }
      
      res.json({
        success: true,
        data: gitInfo
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }

  async handleGitWebhook(req: Request, res: Response): Promise<void> {
    try {
      // Verify webhook signature if configured
      const signature = req.headers['x-hub-signature-256'];
      // TODO: Implement signature verification
      
      const event = req.headers['x-github-event'];
      
      switch (event) {
        case 'pull_request':
          await gitEventHandler.handlePullRequestEvent(req.body);
          break;
        // Add more event handlers as needed
      }
      
      res.json({
        success: true,
        message: 'Webhook processed successfully'
      });
    } catch (error: any) {
      res.status(500).json({
        success: false,
        error: error.message
      });
    }
  }
}