// alert.service.ts
import { Injectable, NotFoundException, BadRequestException, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like } from 'typeorm';
import { Alert } from './entity/alert.entity';
import { AlertStage } from 'common/enum/alert.enum';
import { CreateAlertDto } from './dto/create-alert.dto';
import { ReviewAlertDto } from './dto/review-alert.dto';
import { PublishAlertDto } from './dto/publish-alert.dto';
import { AlertGathererService } from './services/alert-gatherer.service';
import { AlertReviewerService } from './services/alert-reviewer.service';
import { AlertPublisherService } from './services/alert-publisher.service';
import { AlertResponseDto, IAlertResponsePaginated } from './dto/response-alert.dto';
import { updateAlertDto } from './dto/update-alert.dto';
import { FileUploadService } from 'modules/file-upload/file-upload.service';

@Injectable()
export class AlertService {
  private logger = new Logger(AlertService.name);
  constructor(
    @InjectRepository(Alert)
    private alertRepository: Repository<Alert>,
    private alertGathererService: AlertGathererService,
    private alertReviewerService: AlertReviewerService,
    private alertPublisherService: AlertPublisherService,
    private fileUploadService: FileUploadService,
  ) {}

  // Create a new alert (data gathering stage)
  async createAlert(createAlertDto: CreateAlertDto, file: Express.Multer.File): Promise<AlertResponseDto> {
    this.logger.log('Creating a new alert...');
    let alertPosterUrl: string;
    if (file) {
      alertPosterUrl = await this.fileUploadService.uploadImageToCloudinary(file, 'alert');
      this.logger.log('Alert poster URL:', alertPosterUrl);
    }

    const alert = this.alertRepository.create({
      ...createAlertDto,
      stage: AlertStage.GATHERED,
      posterUrl: alertPosterUrl,
    });
    this.logger.log('New alert created', alert);
    return this.alertRepository.save(alert);
  }


  // Fetch external alerts automatically
  async fetchExternalAlerts(options: { page: number; limit: number }): Promise<IAlertResponsePaginated> {
    const { page, limit } = options;
    const skip = (page - 1) * limit;

    this.logger.log('Fetching alerts from all sources...');
    await this.alertGathererService.fetchFromAllSources();

    const alerts = await this.alertRepository.find({
      skip,
      take: limit,
      order: { createdAt: 'DESC' },
    });

    const total = await this.alertRepository.count();

    this.logger.log(`Found ${alerts.length} alerts from all sources`);

    return {
      data: alerts as AlertResponseDto[],
      meta: {
        total,
        page,
        limit,
        totalPages: Math.ceil(total / limit),
      },
    };
  }

  // Find alerts by stage with pagination and search
  async findAlertsByStage(stage: AlertStage, options: { page: number; limit: number; search?: string }): Promise<IAlertResponsePaginated> {
    const { page, limit, search } = options;
    const skip = (page - 1) * limit;

    let whereCondition: any = { stage };

    if (search) {
      whereCondition = [
        { ...whereCondition, title: Like(`%${search}%`) },
        { ...whereCondition, description: Like(`%${search}%`) },
        { ...whereCondition, targetCountry: Like(`%${search}%`) },
        { ...whereCondition, targetOrganization: Like(`%${search}%`) },
      ];
    }

    const [alerts, total] = await this.alertRepository.findAndCount({
      where: whereCondition,
      skip,
      take: limit,
      order: { createdAt: 'ASC' },
    });

    this.logger.log(`Found ${alerts.length} alerts in stage ${stage}`);

    return {
      data: alerts as AlertResponseDto[],
      meta: {
        total,
        page,
        limit,
        totalPages: Math.ceil(total / limit),
      },
    };
  }

  // Find alert by ID
  async findAlertById(id: string): Promise<AlertResponseDto> {
    const alert = await this.alertRepository.findOne({ where: { id } });
    if (!alert) {
      throw new NotFoundException(`Alert with ID ${id} not found`);
    }
    return alert;
  }

  // Move alert to reviewed stage
  async reviewAlert(reviewAlertDto: ReviewAlertDto): Promise<AlertResponseDto> {
    const { id, isVerified, verifiedBy, severity, isRelevantToNepal } = reviewAlertDto;

    const alert = await this.findAlertById(id);

    if (alert.stage !== AlertStage.GATHERED) {
      throw new BadRequestException(`Alert is not in the GATHERED stage`);
    }

    // Update the alert with verification information
    alert.isVerified = isVerified;
    alert.verifiedBy = verifiedBy;
    alert.verifiedAt = new Date();
    alert.stage = AlertStage.REVIEWED;

    if (severity !== undefined) {
      alert.severity = severity;
    }

    if (isRelevantToNepal !== undefined) {
      alert.isRelevantToNepal = isRelevantToNepal;
    }

    // Process through the reviewer service for additional checks
    await this.alertReviewerService.processReview(alert);

    return this.alertRepository.save(alert);
  }

  // Publish an alert
  async publishAlert(publishAlertDto: PublishAlertDto): Promise<AlertResponseDto> {
    const { id, sendToNewsletter } = publishAlertDto;

    const alert = await this.findAlertById(id);

    if (alert.stage !== AlertStage.REVIEWED) {
      throw new BadRequestException(`Alert is not in the REVIEWED stage`);
    }

    // Move to published stage
    alert.stage = AlertStage.PUBLISHED;

    // Send to newsletter if requested
    if (sendToNewsletter) {
      const newsletterId = await this.alertPublisherService.sendToNewsletter(alert);
      alert.sentToNewsletter = true;
      alert.newsletterId = newsletterId;
    }

    return this.alertRepository.save(alert);
  }

  async updateAlert(id: string, updateAlertDto: updateAlertDto): Promise<AlertResponseDto> {
    const alert = await this.findAlertById(id);
    alert.title = updateAlertDto.title;
    alert.description = updateAlertDto.description;
    alert.source = updateAlertDto.source;
    alert.sourceUrl = updateAlertDto.sourceUrl;
    alert.attackTime = updateAlertDto.attackTime;
    alert.targetCountry = updateAlertDto.targetCountry;
    alert.targetOrganization = updateAlertDto.targetOrganization;
    alert.attackerInfo = updateAlertDto.attackerInfo;
    alert.attackType = updateAlertDto.attackType;
    alert.score = updateAlertDto.score;
    alert.severity = updateAlertDto.severity;
    alert.isRelevantToNepal = updateAlertDto.isRelevantToNepal;
    alert.type = updateAlertDto.type;
    return this.alertRepository.save(alert);
  }

  async deleteAlert(id: string): Promise<void> {
    const alert = await this.findAlertById(id);
    await this.alertRepository.remove(alert);
  }
}
