import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectDataSource } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import {
  ListInterventionsDto,
  InterventionAlertDto,
  PaginatedInterventionsDto,
  InterventionStatus,
} from '../dto/interventions';

/**
 * AdminInterventionsService
 *
 * @description Service for managing student intervention alerts in the Admin Portal.
 * Provides CRUD operations for alerts generated by the system to identify
 * at-risk students requiring teacher or admin attention.
 *
 * Features:
 * - List intervention alerts with filters and pagination
 * - Get detailed alert information with student data
 * - Acknowledge alerts (mark as being handled)
 * - Resolve alerts with resolution notes
 * - Dismiss alerts that don't require action
 *
 * Data Sources:
 * - progress_tracking.student_intervention_alerts (main table)
 * - auth_management.profiles (for student/admin names)
 * - social_features.classrooms (for classroom names)
 *
 * @see student_intervention_alerts table schema
 */
@Injectable()
export class AdminInterventionsService {
  constructor(
    @InjectDataSource('progress')
    private readonly dataSource: DataSource,
  ) {}

  /**
   * List intervention alerts with filters and pagination
   *
   * @param filters - Filter and pagination options
   * @returns Paginated list of intervention alerts with student information
   *
   * Query details:
   * - Joins with profiles to get student and admin names
   * - Joins with classrooms to get classroom names
   * - Orders by severity (critical > high > medium > low), then by generated_at DESC
   * - Supports filtering by severity, status, alert_type, student, classroom, date range
   */
  async listInterventions(filters: ListInterventionsDto): Promise<PaginatedInterventionsDto> {
    const {
      severity,
      status,
      alert_type,
      student_id,
      classroom_id,
      date_from,
      date_to,
      page = 1,
      limit = 20,
    } = filters;

    const skip = (page - 1) * limit;

    // Build WHERE clause
    const conditions: string[] = ['1=1'];
    const params: any[] = [];
    let paramIndex = 1;

    if (severity) {
      conditions.push(`a.severity = $${paramIndex}`);
      params.push(severity);
      paramIndex++;
    }

    if (status) {
      conditions.push(`a.status = $${paramIndex}`);
      params.push(status);
      paramIndex++;
    }

    if (alert_type) {
      conditions.push(`a.alert_type = $${paramIndex}`);
      params.push(alert_type);
      paramIndex++;
    }

    if (student_id) {
      conditions.push(`a.student_id = $${paramIndex}`);
      params.push(student_id);
      paramIndex++;
    }

    if (classroom_id) {
      conditions.push(`a.classroom_id = $${paramIndex}`);
      params.push(classroom_id);
      paramIndex++;
    }

    if (date_from) {
      conditions.push(`a.generated_at >= $${paramIndex}`);
      params.push(date_from);
      paramIndex++;
    }

    if (date_to) {
      conditions.push(`a.generated_at <= $${paramIndex}`);
      params.push(date_to);
      paramIndex++;
    }

    const whereClause = conditions.join(' AND ');

    // Query for total count
    const countQuery = `
      SELECT COUNT(*) as total
      FROM progress_tracking.student_intervention_alerts a
      WHERE ${whereClause}
    `;

    const countResult = await this.dataSource.query(countQuery, params);
    const total = parseInt(countResult[0]?.total || '0', 10);

    // Query for data with pagination
    const dataQuery = `
      SELECT
        a.id,
        a.student_id,
        sp.display_name as student_name,
        sp.email as student_email,
        a.classroom_id,
        c.name as classroom_name,
        a.alert_type,
        a.severity,
        a.title,
        a.description,
        a.metrics,
        a.status,
        a.generated_at,
        a.acknowledged_at,
        a.acknowledged_by,
        ap.display_name as acknowledged_by_name,
        a.resolved_at,
        a.resolved_by,
        rp.display_name as resolved_by_name,
        a.resolution_notes,
        a.tenant_id,
        a.created_at,
        a.updated_at
      FROM progress_tracking.student_intervention_alerts a
      INNER JOIN auth_management.profiles sp ON sp.user_id = a.student_id
      LEFT JOIN social_features.classrooms c ON c.id = a.classroom_id
      LEFT JOIN auth_management.profiles ap ON ap.user_id = a.acknowledged_by
      LEFT JOIN auth_management.profiles rp ON rp.user_id = a.resolved_by
      WHERE ${whereClause}
      ORDER BY
        CASE a.severity
          WHEN 'critical' THEN 1
          WHEN 'high' THEN 2
          WHEN 'medium' THEN 3
          WHEN 'low' THEN 4
        END ASC,
        a.generated_at DESC
      LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
    `;

    const dataParams = [...params, limit, skip];
    const rows = await this.dataSource.query(dataQuery, dataParams);

    // Map to DTOs
    const data: InterventionAlertDto[] = rows.map((row: any) => ({
      id: row.id,
      student_id: row.student_id,
      student_name: row.student_name,
      student_email: row.student_email,
      classroom_id: row.classroom_id || undefined,
      classroom_name: row.classroom_name || undefined,
      alert_type: row.alert_type,
      severity: row.severity,
      title: row.title,
      description: row.description || undefined,
      metrics: row.metrics || undefined,
      status: row.status,
      generated_at: row.generated_at,
      acknowledged_at: row.acknowledged_at || undefined,
      acknowledged_by: row.acknowledged_by || undefined,
      acknowledged_by_name: row.acknowledged_by_name || undefined,
      resolved_at: row.resolved_at || undefined,
      resolved_by: row.resolved_by || undefined,
      resolved_by_name: row.resolved_by_name || undefined,
      resolution_notes: row.resolution_notes || undefined,
      tenant_id: row.tenant_id,
      created_at: row.created_at,
      updated_at: row.updated_at,
    }));

    return {
      data,
      total,
      page,
      limit,
      total_pages: Math.ceil(total / limit),
    };
  }

  /**
   * Get a single intervention alert by ID
   *
   * @param id - Alert UUID
   * @returns Intervention alert with full details
   * @throws NotFoundException if alert doesn't exist
   */
  async getInterventionById(id: string): Promise<InterventionAlertDto> {
    const query = `
      SELECT
        a.id,
        a.student_id,
        sp.display_name as student_name,
        sp.email as student_email,
        a.classroom_id,
        c.name as classroom_name,
        a.alert_type,
        a.severity,
        a.title,
        a.description,
        a.metrics,
        a.status,
        a.generated_at,
        a.acknowledged_at,
        a.acknowledged_by,
        ap.display_name as acknowledged_by_name,
        a.resolved_at,
        a.resolved_by,
        rp.display_name as resolved_by_name,
        a.resolution_notes,
        a.tenant_id,
        a.created_at,
        a.updated_at
      FROM progress_tracking.student_intervention_alerts a
      INNER JOIN auth_management.profiles sp ON sp.user_id = a.student_id
      LEFT JOIN social_features.classrooms c ON c.id = a.classroom_id
      LEFT JOIN auth_management.profiles ap ON ap.user_id = a.acknowledged_by
      LEFT JOIN auth_management.profiles rp ON rp.user_id = a.resolved_by
      WHERE a.id = $1
    `;

    const rows = await this.dataSource.query(query, [id]);

    if (!rows || rows.length === 0) {
      throw new NotFoundException(`Intervention alert with ID ${id} not found`);
    }

    const row = rows[0];

    return {
      id: row.id,
      student_id: row.student_id,
      student_name: row.student_name,
      student_email: row.student_email,
      classroom_id: row.classroom_id || undefined,
      classroom_name: row.classroom_name || undefined,
      alert_type: row.alert_type,
      severity: row.severity,
      title: row.title,
      description: row.description || undefined,
      metrics: row.metrics || undefined,
      status: row.status,
      generated_at: row.generated_at,
      acknowledged_at: row.acknowledged_at || undefined,
      acknowledged_by: row.acknowledged_by || undefined,
      acknowledged_by_name: row.acknowledged_by_name || undefined,
      resolved_at: row.resolved_at || undefined,
      resolved_by: row.resolved_by || undefined,
      resolved_by_name: row.resolved_by_name || undefined,
      resolution_notes: row.resolution_notes || undefined,
      tenant_id: row.tenant_id,
      created_at: row.created_at,
      updated_at: row.updated_at,
    };
  }

  /**
   * Acknowledge an intervention alert
   *
   * Changes status from 'active' to 'acknowledged', indicating an admin
   * is aware and working on the intervention.
   *
   * @param id - Alert UUID
   * @param note - Optional acknowledgment note
   * @param userId - ID of admin acknowledging
   * @returns Updated alert
   * @throws NotFoundException if alert doesn't exist
   * @throws BadRequestException if alert is not in 'active' status
   */
  async acknowledgeIntervention(
    id: string,
    note: string | undefined,
    userId: string,
  ): Promise<InterventionAlertDto> {
    // Check current status
    const checkQuery = `
      SELECT status FROM progress_tracking.student_intervention_alerts WHERE id = $1
    `;
    const checkResult = await this.dataSource.query(checkQuery, [id]);

    if (!checkResult || checkResult.length === 0) {
      throw new NotFoundException(`Intervention alert with ID ${id} not found`);
    }

    const currentStatus = checkResult[0].status;

    if (currentStatus !== InterventionStatus.ACTIVE) {
      throw new BadRequestException(
        `Intervention alert can only be acknowledged when status is 'active'. Current status: ${currentStatus}`,
      );
    }

    // Update to acknowledged
    const updateQuery = `
      UPDATE progress_tracking.student_intervention_alerts
      SET
        status = $1,
        acknowledged_by = $2,
        acknowledged_at = gamilit.now_mexico(),
        updated_at = gamilit.now_mexico()
      WHERE id = $3
    `;

    await this.dataSource.query(updateQuery, [InterventionStatus.ACKNOWLEDGED, userId, id]);

    return this.getInterventionById(id);
  }

  /**
   * Resolve an intervention alert
   *
   * Changes status to 'resolved' with required resolution notes.
   * Can only be applied to 'active' or 'acknowledged' alerts.
   *
   * @param id - Alert UUID
   * @param notes - Resolution notes (required, min 10 chars)
   * @param userId - ID of admin resolving
   * @returns Updated alert
   * @throws NotFoundException if alert doesn't exist
   * @throws BadRequestException if alert cannot be resolved
   */
  async resolveIntervention(id: string, notes: string, userId: string): Promise<InterventionAlertDto> {
    // Check current status
    const checkQuery = `
      SELECT status FROM progress_tracking.student_intervention_alerts WHERE id = $1
    `;
    const checkResult = await this.dataSource.query(checkQuery, [id]);

    if (!checkResult || checkResult.length === 0) {
      throw new NotFoundException(`Intervention alert with ID ${id} not found`);
    }

    const currentStatus = checkResult[0].status;

    if (currentStatus !== InterventionStatus.ACTIVE && currentStatus !== InterventionStatus.ACKNOWLEDGED) {
      throw new BadRequestException(
        `Intervention alert can only be resolved when status is 'active' or 'acknowledged'. Current status: ${currentStatus}`,
      );
    }

    // Update to resolved
    const updateQuery = `
      UPDATE progress_tracking.student_intervention_alerts
      SET
        status = $1,
        resolution_notes = $2,
        resolved_by = $3,
        resolved_at = gamilit.now_mexico(),
        updated_at = gamilit.now_mexico()
      WHERE id = $4
    `;

    await this.dataSource.query(updateQuery, [InterventionStatus.RESOLVED, notes, userId, id]);

    return this.getInterventionById(id);
  }

  /**
   * Dismiss an intervention alert
   *
   * Changes status to 'dismissed' for alerts that don't require action
   * (false positives or not relevant).
   *
   * @param id - Alert UUID
   * @returns Updated alert
   * @throws NotFoundException if alert doesn't exist
   */
  async dismissIntervention(id: string): Promise<InterventionAlertDto> {
    // Check if exists
    const checkQuery = `
      SELECT id FROM progress_tracking.student_intervention_alerts WHERE id = $1
    `;
    const checkResult = await this.dataSource.query(checkQuery, [id]);

    if (!checkResult || checkResult.length === 0) {
      throw new NotFoundException(`Intervention alert with ID ${id} not found`);
    }

    // Update to dismissed
    const updateQuery = `
      UPDATE progress_tracking.student_intervention_alerts
      SET
        status = $1,
        updated_at = gamilit.now_mexico()
      WHERE id = $2
    `;

    await this.dataSource.query(updateQuery, [InterventionStatus.DISMISSED, id]);

    return this.getInterventionById(id);
  }
}
