import * as plugins from '../../plugins.js';
import { CachedDocument, TTL } from '../classes.cached.document.js';
import { DcRouterDb } from '../classes.dcrouter-db.js';

/**
 * Helper to get the smartdata database instance
 */
const getDb = () => DcRouterDb.getInstance().getDb();

/**
 * IP reputation result data
 */
export interface IIPReputationData {
  score: number;
  isSpam: boolean;
  isProxy: boolean;
  isTor: boolean;
  isVPN: boolean;
  country?: string;
  asn?: string;
  org?: string;
  blacklists?: string[];
}

/**
 * CachedIPReputation - Stores IP reputation lookup results
 *
 * Caches the results of IP reputation checks to avoid repeated
 * external API calls. Default TTL is 24 hours.
 */
@plugins.smartdata.Collection(() => getDb())
export class CachedIPReputation extends CachedDocument<CachedIPReputation> {
  // TTL fields from base class (decorators required on concrete class)
  @plugins.smartdata.svDb()
  public createdAt: Date = new Date();

  @plugins.smartdata.svDb()
  public expiresAt: Date = new Date(Date.now() + TTL.HOURS_24);

  @plugins.smartdata.svDb()
  public lastAccessedAt: Date = new Date();

  /**
   * IP address (unique identifier)
   */
  @plugins.smartdata.unI()
  @plugins.smartdata.svDb()
  public ipAddress!: string;

  /**
   * Reputation score (0-100, higher = better)
   */
  @plugins.smartdata.svDb()
  public score!: number;

  /**
   * Whether the IP is flagged as spam source
   */
  @plugins.smartdata.svDb()
  public isSpam!: boolean;

  /**
   * Whether the IP is a known proxy
   */
  @plugins.smartdata.svDb()
  public isProxy!: boolean;

  /**
   * Whether the IP is a Tor exit node
   */
  @plugins.smartdata.svDb()
  public isTor!: boolean;

  /**
   * Whether the IP is a VPN endpoint
   */
  @plugins.smartdata.svDb()
  public isVPN!: boolean;

  /**
   * Country code (ISO 3166-1 alpha-2)
   */
  @plugins.smartdata.svDb()
  public country!: string;

  /**
   * Autonomous System Number
   */
  @plugins.smartdata.svDb()
  public asn!: string;

  /**
   * Organization name
   */
  @plugins.smartdata.svDb()
  public org!: string;

  /**
   * List of blacklists the IP appears on
   */
  @plugins.smartdata.svDb()
  public blacklists!: string[];

  /**
   * Number of times this IP has been checked
   */
  @plugins.smartdata.svDb()
  public checkCount: number = 0;

  /**
   * Number of connections from this IP
   */
  @plugins.smartdata.svDb()
  public connectionCount: number = 0;

  /**
   * Number of emails received from this IP
   */
  @plugins.smartdata.svDb()
  public emailCount: number = 0;

  /**
   * Number of spam emails from this IP
   */
  @plugins.smartdata.svDb()
  public spamCount: number = 0;

  constructor() {
    super();
    this.setTTL(TTL.HOURS_24); // Default 24-hour TTL
    this.blacklists = [];
    this.score = 50; // Default neutral score
    this.isSpam = false;
    this.isProxy = false;
    this.isTor = false;
    this.isVPN = false;
  }

  /**
   * Create from reputation data
   */
  public static fromReputationData(ipAddress: string, data: IIPReputationData): CachedIPReputation {
    const cached = new CachedIPReputation();
    cached.ipAddress = ipAddress;
    cached.score = data.score;
    cached.isSpam = data.isSpam;
    cached.isProxy = data.isProxy;
    cached.isTor = data.isTor;
    cached.isVPN = data.isVPN;
    cached.country = data.country || '';
    cached.asn = data.asn || '';
    cached.org = data.org || '';
    cached.blacklists = data.blacklists || [];
    cached.checkCount = 1;
    return cached;
  }

  /**
   * Convert to reputation data object
   */
  public toReputationData(): IIPReputationData {
    this.touch();
    return {
      score: this.score,
      isSpam: this.isSpam,
      isProxy: this.isProxy,
      isTor: this.isTor,
      isVPN: this.isVPN,
      country: this.country,
      asn: this.asn,
      org: this.org,
      blacklists: this.blacklists,
    };
  }

  /**
   * Find by IP address
   */
  public static async findByIP(ipAddress: string): Promise<CachedIPReputation | null> {
    return await CachedIPReputation.getInstance({
      ipAddress,
    });
  }

  /**
   * Find all IPs flagged as spam
   */
  public static async findSpamIPs(): Promise<CachedIPReputation[]> {
    return await CachedIPReputation.getInstances({
      isSpam: true,
    });
  }

  /**
   * Find IPs with score below threshold
   */
  public static async findLowScoreIPs(threshold: number): Promise<CachedIPReputation[]> {
    return await CachedIPReputation.getInstances({
      score: { $lt: threshold },
    });
  }

  /**
   * Record a connection from this IP
   */
  public recordConnection(): void {
    this.connectionCount++;
    this.touch();
  }

  /**
   * Record an email from this IP
   */
  public recordEmail(isSpam: boolean = false): void {
    this.emailCount++;
    if (isSpam) {
      this.spamCount++;
    }
    this.touch();
  }

  /**
   * Update the reputation data
   */
  public updateReputation(data: IIPReputationData): void {
    this.score = data.score;
    this.isSpam = data.isSpam;
    this.isProxy = data.isProxy;
    this.isTor = data.isTor;
    this.isVPN = data.isVPN;
    this.country = data.country || this.country;
    this.asn = data.asn || this.asn;
    this.org = data.org || this.org;
    this.blacklists = data.blacklists || this.blacklists;
    this.checkCount++;
    this.touch();
    // Refresh TTL on update
    this.setTTL(TTL.HOURS_24);
  }

  /**
   * Check if this IP should be blocked
   */
  public shouldBlock(): boolean {
    return this.isSpam || this.score < 20 || this.blacklists.length > 2;
  }
}
