import crypto from 'crypto';
import { PlantData, BlockData } from './types';

/**
 * PlantBlock - Represents a single block in the plant blockchain
 * Each block contains data about a plant and its lineage
 */
export class PlantBlock {
  public index: number;
  public timestamp: string;
  public plant: PlantData;
  public previousHash: string;
  public hash: string;
  public nonce: number;

  constructor(
    index: number,
    timestamp: string,
    plant: PlantData,
    previousHash: string = ''
  ) {
    this.index = index;
    this.timestamp = timestamp;
    this.plant = plant;
    this.previousHash = previousHash;
    this.nonce = 0;
    this.hash = this.calculateHash();
  }

  /**
   * Calculate the hash of this block using SHA-256
   */
  calculateHash(): string {
    return crypto
      .createHash('sha256')
      .update(
        this.index +
          this.previousHash +
          this.timestamp +
          JSON.stringify(this.plant) +
          this.nonce
      )
      .digest('hex');
  }

  /**
   * Mine the block using proof-of-work algorithm
   * Difficulty determines how many leading zeros the hash must have
   */
  mineBlock(difficulty: number): void {
    const target = Array(difficulty + 1).join('0');

    while (this.hash.substring(0, difficulty) !== target) {
      this.nonce++;
      this.hash = this.calculateHash();
    }

    console.log(`Block mined: ${this.hash}`);
  }

  /**
   * Convert block to JSON for storage/transmission
   */
  toJSON(): BlockData {
    return {
      index: this.index,
      timestamp: this.timestamp,
      plant: this.plant,
      previousHash: this.previousHash,
      hash: this.hash,
      nonce: this.nonce,
    };
  }

  /**
   * Create a PlantBlock from JSON data
   */
  static fromJSON(data: BlockData): PlantBlock {
    const block = new PlantBlock(
      data.index,
      data.timestamp,
      data.plant,
      data.previousHash
    );
    block.hash = data.hash;
    block.nonce = data.nonce;
    return block;
  }

  /**
   * Verify if this block is valid
   */
  isValid(previousBlock?: PlantBlock): boolean {
    // Check if hash is correct
    if (this.hash !== this.calculateHash()) {
      return false;
    }

    // Check if previous hash matches
    if (previousBlock && this.previousHash !== previousBlock.hash) {
      return false;
    }

    return true;
  }
}
