import { Injectable, Logger } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { HttpService } from '@nestjs/axios';
import { Alert } from '../entity/alert.entity';
import { AlertStage, AlertType, AttackType } from 'common/enum/alert.enum';
import { firstValueFrom } from 'rxjs';
import * as cheerio from 'cheerio';
import { ConfigService } from '@nestjs/config';
import * as net from 'net';
import { cyberKeywords } from 'modules/crawler/keywords/crawler.keywords';
import axios from 'axios';

@Injectable()
export class AlertGathererService {
  private readonly logger = new Logger(AlertGathererService.name);

  constructor(
    @InjectRepository(Alert)
    private alertRepository: Repository<Alert>,
    private httpService: HttpService,
    private configService: ConfigService,
  ) {}

  // Main method to fetch from all sources
  async fetchFromAllSources(): Promise<void> {
    try {
      await Promise.all([
        this.fetchFromVirusTotalAPI(),
        this.fetchFromThreatIntelFeeds(),
        this.fetchFromSecurityNews(),
        this.fetchFromNepalCERTFeed(),
        this.fetchFromCISAFeed(),
        this.fetchTechPanaNews(),
        // this.fetchThreatIntelFromEmergingThreats(),
        // this.fetchFromHIBP(),
        // this.fetchFromShodan(),
        // this.fetchCyberNews(),
      ]);
      this.logger.log('Successfully fetched data from all sources');
    } catch (error) {
      this.logger.error(`Error fetching data: ${error.message}`);
    }
  }

  // Fetch from VirusTotal API
  private async fetchFromVirusTotalAPI(): Promise<void> {
    try {
      this.logger.log('Fetching data from VirusTotal API...');
      const apiKey = this.configService.get<string>('VIRUS_TOTAL_API_KEY');
      const response = await firstValueFrom(
        this.httpService.get('https://www.virustotal.com/api/v3/urls/id', {
          headers: { 'x-apikey': apiKey },
        }),
      );

      const data = response.data.data;

      for (const item of data) {
        // Check if this alert already exists in our system
        this.logger.log(`Processing item: ${item.id}`);
        const existingAlert = await this.alertRepository.findOne({
          where: {
            source: 'VirusTotal',
            sourceUrl: `https://www.virustotal.com/gui/file/${item.id}`,
          },
        });

        if (!existingAlert) {
          this.logger.log(`Creating new alert for item: ${JSON.stringify(item)}`);
          const newAlert = this.alertRepository.create({
            title: `Malware detected: ${item.attributes.meaningful_name}`,
            description: `Detection ratio: ${item.attributes.last_analysis_stats.malicious}/${
              item.attributes.last_analysis_stats.malicious + item.attributes.last_analysis_stats.undetected
            }`,
            source: 'VirusTotal',
            sourceUrl: `https://www.virustotal.com/gui/file/${item.id}`,
            attackTime: new Date(item.attributes.last_analysis_date * 1000),
            targetCountry: item.attributes.country || 'Unknown',
            targetOrganization: 'Various',
            attackType: AttackType.MALWARE,
            stage: AlertStage.GATHERED,
            type: AlertType.AUTOMATIC,
            isRelevantToNepal: item.attributes.country === 'NP',
          });

          await this.alertRepository.save(newAlert);
        }
      }
      this.logger.log(`Successfully fetched data from VirusTotal API`);
    } catch (error) {
      this.logger.error(`Error fetching from VirusTotal: ${error.message}`);
    }
  }

  // Fetch from Threat Intelligence Feeds
  private async fetchFromThreatIntelFeeds(): Promise<void> {
    try {
      // Example: Fetching from AlienVault OTX
      const apiKey = this.configService.get<string>('ALIENVAULT_API_KEY');
      const response = await firstValueFrom(
        this.httpService.get('https://otx.alienvault.com/api/v1/pulses/subscribed', {
          headers: { 'X-OTX-API-KEY': apiKey },
        }),
      );

      const pulses = response.data.results;

      this.logger.log(`Fetched ${JSON.stringify(pulses[0])} pulses from AlienVault OTX`);
      for (const pulse of pulses) {
        // Check if this pulse already exists
        const existingAlert = await this.alertRepository.findOne({
          where: {
            source: 'AlienVault OTX',
            sourceUrl: `https://otx.alienvault.com/pulse/${pulse.id}`,
          },
        });

        if (!existingAlert) {
          // Determine attack type based on pulse tags
          let attackType = AttackType.OTHER;
          if (pulse.tags.includes('malware')) {
            attackType = AttackType.MALWARE;
          } else if (pulse.tags.includes('ransomware')) {
            attackType = AttackType.RANSOMWARE;
          } else if (pulse.tags.includes('phishing')) {
            attackType = AttackType.PHISHING;
          } else if (pulse.tags.includes('ddos')) {
            attackType = AttackType.DDOS;
          } else if (pulse.tags.includes('data breach')) {
            attackType = AttackType.DATA_BREACH;
          }

          // Check if Nepal is mentioned
          const isRelevantToNepal = pulse.targeted_countries?.includes('NP') || pulse.description?.toLowerCase().includes('nepal');

          const newAlert = this.alertRepository.create({
            title: pulse.name,
            description: pulse.description,
            source: 'AlienVault OTX',
            sourceUrl: `https://otx.alienvault.com/pulse/${pulse.id}`,
            attackTime: new Date(pulse.created),
            targetCountry: pulse.targeted_countries?.join(', ') || 'Unknown',
            targetOrganization: pulse.industries?.join(', ') || 'Various',
            attackerInfo: pulse.author_name,
            attackType,
            stage: AlertStage.GATHERED,
            type: AlertType.AUTOMATIC,
            isRelevantToNepal,
          });

          await this.alertRepository.save(newAlert);
        }
      }
      this.logger.log(`Successfully fetched data from Threat Intelligence Feeds`);
    } catch (error) {
      this.logger.error(`Error fetching from Threat Intel Feeds: ${error.message}`);
    }
  }

  // Fetch from Security News
  private async fetchFromSecurityNews(): Promise<void> {
    try {
      // Example: Fetch from TheHackerNews RSS
      const response = await firstValueFrom(this.httpService.get('https://feeds.feedburner.com/TheHackersNews'));

      // Parse XML RSS feed
      const $ = cheerio.load(response.data, { xmlMode: true });

      $('item').each((i, item) => {
        (async () => {
          const title = $(item).find('title').text();
          const link = $(item).find('link').text();
          const description = $(item).find('description').text();
          const pubDate = $(item).find('pubDate').text();

          // Check if this news already exists
          const existingAlert = await this.alertRepository.findOne({
            where: {
              source: 'TheHackerNews',
              sourceUrl: link,
            },
          });

          if (!existingAlert) {
            // Determine attack type based on keywords in title and description
            let attackType = AttackType.OTHER;
            const content = title.toLowerCase() + ' ' + description.toLowerCase();

            if (content.includes('malware')) {
              attackType = AttackType.MALWARE;
            } else if (content.includes('ransomware')) {
              attackType = AttackType.RANSOMWARE;
            } else if (content.includes('phishing')) {
              attackType = AttackType.PHISHING;
            } else if (content.includes('ddos') || content.includes('denial of service')) {
              attackType = AttackType.DDOS;
            } else if (content.includes('data breach') || content.includes('leak')) {
              attackType = AttackType.DATA_BREACH;
            }

            // Check if Nepal is mentioned
            const isRelevantToNepal = content.includes('nepal');

            const newAlert = this.alertRepository.create({
              title,
              description: cheerio.load(description).text().substring(0, 500) + '...',
              source: 'TheHackerNews',
              sourceUrl: link,
              attackTime: new Date(pubDate),
              targetCountry: isRelevantToNepal ? 'Nepal' : 'Various',
              targetOrganization: 'Various',
              attackType,
              stage: AlertStage.GATHERED,
              type: AlertType.AUTOMATIC,
              isRelevantToNepal,
            });

            await this.alertRepository.save(newAlert);
          }
        })();
      });
      this.logger.log(`Successfully fetched data from Security News`);
    } catch (error) {
      this.logger.error(`Error fetching from Security News: ${error.message}`);
    }
  }

  // Fetch from Nepal CERT Feed
  private async fetchFromNepalCERTFeed(): Promise<void> {
    try {
      // Nepal CERT website may not have an RSS feed, so we'll simulate scraping
      const response = await firstValueFrom(this.httpService.get('https://www.nepalcert.gov.np/advisories'));

      const $ = cheerio.load(response.data);

      // Assuming the structure of the page, adjust selectors as needed
      $('.advisory-item').each((i, element) => {
        const title = $(element).find('.advisory-title').text().trim();
        const link = 'https://www.nepalcert.gov.np' + $(element).find('a').attr('href');
        const description = $(element).find('.advisory-description').text().trim();
        const dateStr = $(element).find('.advisory-date').text().trim();

        // Check if this advisory already exists
        const existingAlert = this.alertRepository.findOne({
          where: {
            source: 'Nepal CERT',
            sourceUrl: link,
          },
        });

        if (!existingAlert && title) {
          // Determine attack type based on keywords
          let attackType = AttackType.OTHER;
          const content = title.toLowerCase() + ' ' + description.toLowerCase();

          if (content.includes('malware')) {
            attackType = AttackType.MALWARE;
          } else if (content.includes('ransomware')) {
            attackType = AttackType.RANSOMWARE;
          } else if (content.includes('phishing')) {
            attackType = AttackType.PHISHING;
          } else if (content.includes('ddos') || content.includes('denial of service')) {
            attackType = AttackType.DDOS;
          } else if (content.includes('data breach') || content.includes('leak')) {
            attackType = AttackType.DATA_BREACH;
          }

          const newAlert = this.alertRepository.create({
            title,
            description,
            source: 'Nepal CERT',
            sourceUrl: link,
            attackTime: dateStr ? new Date(dateStr) : new Date(),
            targetCountry: 'Nepal',
            targetOrganization: 'Various Nepali Organizations',
            attackType,
            stage: AlertStage.GATHERED,
            type: AlertType.AUTOMATIC,
            isRelevantToNepal: true,
            severity: 3, // Default medium severity for CERT advisories
          });

          this.alertRepository.save(newAlert);
        }
      });
      this.logger.log(`Successfully fetched data from Nepal CERT`);
    } catch (error) {
      this.logger.error(`Error fetching from Nepal CERT: ${error.message}`);
    }
  }

  // Fetch from CISA Feed
  private async fetchFromCISAFeed(): Promise<void> {
    this.logger.log('Fetching data from CISA feed...');
    try {
      // Example: Fetch from CISA RSS
      const response = await firstValueFrom(this.httpService.get('https://www.cisa.gov/api/kev/v1.0/catalog/feeds/cisa'));

      const data = response.data;

      this.logger.log(`Fetched ${data.length} alerts from CISA`);
      for (const item of data) {
        // Check if this alert already exists
        const existingAlert = await this.alertRepository.findOne({
          where: {
            source: 'CISA',
            sourceUrl: item.url,
          },
        });

        if (!existingAlert) {
          const newAlert = this.alertRepository.create({
            title: item.title,
            description: item.description,
            source: 'CISA',
            sourceUrl: item.url,
            attackTime: new Date(item.date),
            targetCountry: 'United States',
            targetOrganization: 'Various',
            attackType: AttackType.OTHER,
            stage: AlertStage.GATHERED,
            type: AlertType.AUTOMATIC,
            isRelevantToNepal: false,
          });

          await this.alertRepository.save(newAlert);
        }
      }
    } catch (error) {
      this.logger.error(`Error fetching from CISA: ${error.message}`);
    }
  }

  private async fetchThreatIntelFromEmergingThreats(): Promise<void> {
    try {
      this.logger.log('Fetching latest compromised IPs from Emerging Threats...');

      const response = await firstValueFrom(this.httpService.get('https://rules.emergingthreats.net/blockrules/compromised-ips.txt'));

      const lines = response.data.split('\n');

      for (const line of lines) {
        // Skip empty lines or comments
        if (!line.trim() || line.startsWith('#')) continue;

        // Extract IP and optional description
        const parts = line.split('#');
        const ip = parts[0].trim();
        const description = parts[1]?.trim() || 'Compromised IP detected';

        // Validate IP format
        if (!net.isIP(ip)) continue;

        // Check if this alert already exists
        const existingAlert = await this.alertRepository.findOne({
          where: { source: 'Emerging Threats', title: ip },
        });

        if (!existingAlert) {
          // Get IP geolocation
          const geoInfo = await this.getIpGeolocation(ip);
          const country = geoInfo?.country || 'Unknown';
          const isRelevantToNepal = country === 'Nepal';

          const newAlert = this.alertRepository.create({
            title: `Compromised IP: ${ip}`,
            description,
            source: 'Emerging Threats',
            attackTime: new Date(),
            targetCountry: country,
            targetOrganization: geoInfo?.isp || 'Unknown',
            attackType: AttackType.DDOS,
            stage: AlertStage.GATHERED,
            type: AlertType.AUTOMATIC,
            isRelevantToNepal,
          });

          await this.alertRepository.save(newAlert);
        }
      }
      this.logger.log(`Successfully stored compromised IPs from Emerging Threats.`);
    } catch (error) {
      this.logger.error(`Error fetching from Emerging Threats: ${error.message}`);
    }
  }

  /**
   * Fetches geolocation details for an IP address using ip-api.com.
   * @param ip - The IP address to lookup.
   * @returns An object containing country, ISP, and other metadata.
   */
  private async getIpGeolocation(ip: string): Promise<{ country: string; isp: string } | null> {
    try {
      const response = await firstValueFrom(this.httpService.get(`http://ip-api.com/json/${ip}`));
      return {
        country: response.data.country || 'Unknown',
        isp: response.data.isp || 'Unknown',
      };
    } catch (error) {
      this.logger.warn(`Failed to get geolocation for IP ${ip}: ${error.message}`);
      return null; // Return null on failure
    }
  }

  private async fetchTechPanaNews(): Promise<void> {
    try {
      this.logger.log('Fetching data from TechPana...');

      const response = await axios.get('https://techpana.com');
      const $ = cheerio.load(response.data);
      // Each article is inside this structure
      const articles = $('.newsTech_section-wrapper .grid_section-content .single_row-wrapper');

      for (const element of articles.toArray()) {
        const title = $(element).find('.single_row-title a').text().trim();
        const link = $(element).find('.single_row-title a').attr('href');
        const description = $(element).find('.single_row-side-info p').text().trim() || title;

        const content = `${title} ${description}`.toLowerCase();
        const isCyberRelated = cyberKeywords.some(keyword => content.includes(keyword));

        if (!isCyberRelated) {
          this.logger.log(`Skipping non-cyber related article: ${title}`);
          continue;
        }

        const existingAlert = await this.alertRepository.findOne({
          where: {
            source: 'TechPana',
            sourceUrl: `https://techpana.com${link}`,
          },
        });

        if (!existingAlert) {
          // Detect attack type
          let attackType = AttackType.OTHER;
          if (content.includes('malware')) attackType = AttackType.MALWARE;
          else if (content.includes('ransomware')) attackType = AttackType.RANSOMWARE;
          else if (content.includes('phishing')) attackType = AttackType.PHISHING;
          else if (content.includes('ddos') || content.includes('denial of service')) attackType = AttackType.DDOS;
          else if (content.includes('data breach') || content.includes('leak')) attackType = AttackType.DATA_BREACH;
          else if (content.includes('cyber attack') || content.includes('cyber threat')) attackType = AttackType.CYBER_ATTACK;
          else if (content.includes('exploit')) attackType = AttackType.EXPLOIT;
          else if (content.includes('scam')) attackType = AttackType.SCAM;
          else if (content.includes('social engineering')) attackType = AttackType.SOCIAL_ENGINEERING;
          else if (content.includes('spam')) attackType = AttackType.SPAM;
          else if (content.includes('botnet')) attackType = AttackType.BOTNET;
          else if (content.includes('apt') || content.includes('advanced persistent threat')) attackType = AttackType.APT;
          else if (content.includes('sql injection')) attackType = AttackType.SQL_INJECTION;
          else if (content.includes('xss') || content.includes('cross-site scripting')) attackType = AttackType.XSS;
          else if (content.includes('csrf') || content.includes('cross-site request forgery')) attackType = AttackType.CSRF;
          else if (content.includes('mitm') || content.includes('man-in-the-middle')) attackType = AttackType.MITM;
          else {
            attackType = AttackType.OTHER;
          }

          const newAlert = this.alertRepository.create({
            title,
            description: description.substring(0, 500) + '...',
            source: 'TechPana',
            sourceUrl: `https://techpana.com${link}`,
            attackTime: new Date(),
            targetCountry: 'Nepal',
            targetOrganization: 'Various',
            attackType,
            stage: AlertStage.GATHERED,
            type: AlertType.AUTOMATIC,
            isRelevantToNepal: true,
          });

          this.logger.log(`Creating new alert for TechPana: ${title}`);
          await this.alertRepository.save(newAlert);
        }
      }

      this.logger.log('Successfully fetched data from TechPana');
    } catch (error) {
      this.logger.error(`Error fetching from TechPana: ${error.message}`);
    }
  }

  // private async fetchFromHIBP(): Promise<void> {
  //     try {
  //         this.logger.log('Fetching data from Have I Been Pwned API...');

  //         const apiKey = this.configService.get<string>('HIBP_API_KEY');
  //         const response = await firstValueFrom(
  //             this.httpService.get('https://haveibeenpwned.com/api/v3/breaches', {
  //                 headers: {
  //                     'hibp-api-key': apiKey,
  //                 }
  //             })
  //         );

  //         const breaches = response.data;

  //         for (const breach of breaches) {
  //             // Check if this breach alert already exists
  //             const existingAlert = await this.alertRepository.findOne({
  //                 where: {
  //                     source: 'Have I Been Pwned',
  //                     sourceUrl: breach.Domain ? `https://${breach.Domain}` : breach.BreachDate,
  //                 },
  //             });

  //             if (!existingAlert) {
  //                 this.logger.log(`Creating new alert for breach: ${breach.Name}`);

  //                 const newAlert = this.alertRepository.create({
  //                     title: `Data Breach: ${breach.Name}`,
  //                     description: `Breach of ${breach.Domain || 'Unknown domain'} exposing ${breach.PwnCount} accounts. Data types: ${breach.DataClasses.join(', ')}`,
  //                     source: 'Have I Been Pwned',
  //                     sourceUrl: breach.Domain ? `https://${breach.Domain}` : breach.BreachDate,
  //                     attackTime: new Date(breach.BreachDate),
  //                     targetCountry: 'Various',
  //                     targetOrganization: breach.Domain || 'Unknown',
  //                     attackType: AttackType.DATA_BREACH,
  //                     stage: AlertStage.GATHERED,
  //                     type: AlertType.AUTOMATIC,
  //                     isRelevantToNepal: breach.Domain?.includes('.np') || false,
  //                 });

  //                 await this.alertRepository.save(newAlert);
  //             }
  //         }
  //         this.logger.log('Successfully fetched data from Have I Been Pwned API');
  //     } catch (error) {
  //         this.logger.error(`Error fetching from Have I Been Pwned: ${error.message}`);
  //     }
  // }

  // private async fetchFromShodan(): Promise<void> {
  //     try {
  //         this.logger.log('Fetching data from Shodan...');
  //         const apiKey = this.configService.get<string>('SHODAN_API_KEY');

  //         // Fetching data from Shodan's API (example: search for vulnerabilities)
  //         const response = await firstValueFrom(
  //             this.httpService.get(`https://api.shodan.io/shodan/host/search?key=${apiKey}&query=vuln`)
  //         );

  //         this.logger.log(`Fetched ${JSON.stringify(response.data)} items from Shodan`);
  //         const data = response.data.matches;

  //         for (const item of data) {
  //             this.logger.log(`Processing item: ${item.ip_str}`);

  //             // Check if this alert already exists in our system
  //             const existingAlert = await this.alertRepository.findOne({
  //                 where: {
  //                     source: 'Shodan',
  //                     sourceUrl: `https://www.shodan.io/host/${item.ip_str}`,
  //                 },
  //             });

  //             if (!existingAlert) {
  //                 this.logger.log(`Creating new alert for IP: ${item.ip_str}`);
  //                 const newAlert = this.alertRepository.create({
  //                     title: `Vulnerability detected on IP: ${item.ip_str}`,
  //                     description: `Port: ${item.port}, Vulnerability: ${item.vulns ? Object.keys(item.vulns).join(', ') : 'N/A'}`,
  //                     source: 'Shodan',
  //                     sourceUrl: `https://www.shodan.io/host/${item.ip_str}`,
  //                     attackTime: new Date(),
  //                     targetCountry: item.location.country || 'Unknown',
  //                     targetOrganization: item.org || 'Various',
  //                     attackType: AttackType.OTHER, // You can categorize it based on the vulnerability
  //                     stage: AlertStage.GATHERED,
  //                     type: AlertType.AUTOMATIC,
  //                     isRelevantToNepal: item.location.country === 'NP', // Check if it's relevant to Nepal
  //                 });

  //                 await this.alertRepository.save(newAlert);
  //             }
  //         }
  //         this.logger.log('Successfully fetched data from Shodan');
  //     } catch (error) {
  //         this.logger.error(`Error fetching from Shodan: ${error.message}`);
  //     }
  // }

  // private async fetchCyberNews(): Promise<void> {
  //     try {
  //         // Nepal CERT website may not have an RSS feed, so we'll simulate scraping
  //         const response = await firstValueFrom(
  //             this.httpService.get('https://www.nepalpolice.gov.np')
  //         );

  //         const $ = cheerio.load(response.data);

  //         this.logger.log(`Fetched news from Nepal Police `, response.data);
  //         // Assuming the structure of the page, adjust selectors as needed
  //         $('.newsbar-container').each((i, element) => {
  //             const title = $(element).find('.newsbar-title').text().trim();
  //             const link = 'https://www.nepalpolice.gov.np' + $(element).find('a').attr('href');
  //             const description = $(element).find('.newsbar-description').text().trim();
  //             const dateStr = $(element).find('.newsbar-date').text().trim();

  //             this.logger.log(`Processing news: ${title}`);
  //             // Check if this news already exists
  //             const existingAlert = this.alertRepository.findOne({
  //                 where: {
  //                     source: 'Nepal Police',
  //                     sourceUrl: link,
  //                 },
  //             });

  //             if (!existingAlert && title) {
  //                 // Determine attack type based on keywords
  //                 let attackType = AttackType.OTHER;
  //                 const content = title.toLowerCase() + ' ' + description.toLowerCase();

  //                 if (content.includes('malware')) {
  //                     attackType = AttackType.MALWARE;
  //                 } else if (content.includes('ransomware')) {
  //                     attackType = AttackType.RANSOMWARE;
  //                 } else if (content.includes('phishing')) {
  //                     attackType = AttackType.PHISHING;
  //                 } else if (content.includes('ddos') || content.includes('denial of service')) {
  //                     attackType = AttackType.DDOS;
  //                 } else if (content.includes('data breach') || content.includes('leak')) {
  //                     attackType = AttackType.DATA_BREACH;
  //                 }

  //                 const newAlert = this.alertRepository.create({
  //                     title,
  //                     description: cheerio.load(description).text().substring(0, 500) + '...',
  //                     source: 'Nepal Police',
  //                     sourceUrl: link,
  //                     attackTime: new Date(dateStr),
  //                     targetCountry: 'Nepal',
  //                     targetOrganization: 'Various',
  //                     attackType,
  //                     stage: AlertStage.GATHERED,
  //                     type: AlertType.AUTOMATIC,
  //                     isRelevantToNepal: true,
  //                 });

  //                 this.alertRepository.save(newAlert);
  //             }
  //         });
  //     } catch (error) {
  //         this.logger.error(`Error fetching from Nepal CERT: ${error.message}`);
  //     }
  // }
}
