/**
 * PlantChain Tests
 * Tests for the blockchain implementation
 */

import { PlantChain } from '../../../lib/blockchain/PlantChain';
import { PlantData } from '../../../lib/blockchain/types';

describe('PlantChain', () => {
  let chain: PlantChain;

  beforeEach(() => {
    chain = new PlantChain();
  });

  describe('Initialization', () => {
    it('should create chain with genesis block', () => {
      expect(chain.getChain().length).toBe(1);
    });

    it('should have valid genesis block', () => {
      const genesisBlock = chain.getChain()[0];
      expect(genesisBlock.index).toBe(0);
      expect(genesisBlock.previousHash).toBe('0');
    });
  });

  describe('Adding Plants', () => {
    const createTestPlant = (overrides?: Partial<PlantData>): PlantData => ({
      id: `plant-${Date.now()}`,
      name: 'Test Plant',
      species: 'Test Species',
      variety: 'Test Variety',
      generation: 1,
      propagationType: 'original',
      dateAcquired: new Date().toISOString(),
      location: {
        latitude: 40.7128,
        longitude: -74.006,
        city: 'New York',
      },
      status: 'healthy',
      ...overrides,
    });

    it('should add new plant to chain', () => {
      const plant = createTestPlant();
      chain.addPlant(plant);
      expect(chain.getChain().length).toBe(2);
    });

    it('should generate valid block hash', () => {
      const plant = createTestPlant();
      chain.addPlant(plant);
      const newBlock = chain.getChain()[1];
      expect(newBlock.hash).toBeDefined();
      expect(newBlock.hash.length).toBeGreaterThan(0);
    });

    it('should link blocks correctly', () => {
      const plant = createTestPlant();
      chain.addPlant(plant);
      const genesisBlock = chain.getChain()[0];
      const newBlock = chain.getChain()[1];
      expect(newBlock.previousHash).toBe(genesisBlock.hash);
    });

    it('should store plant data correctly', () => {
      const plant = createTestPlant({ name: 'My Tomato' });
      chain.addPlant(plant);
      const newBlock = chain.getChain()[1];
      expect(newBlock.plant.name).toBe('My Tomato');
    });

    it('should add multiple plants', () => {
      chain.addPlant(createTestPlant({ id: 'plant-1' }));
      chain.addPlant(createTestPlant({ id: 'plant-2' }));
      chain.addPlant(createTestPlant({ id: 'plant-3' }));
      expect(chain.getChain().length).toBe(4);
    });
  });

  describe('Finding Plants', () => {
    beforeEach(() => {
      chain.addPlant({
        id: 'tomato-1',
        name: 'Cherry Tomato',
        species: 'Tomato',
        variety: 'Cherry',
        generation: 1,
        propagationType: 'original',
        dateAcquired: new Date().toISOString(),
        location: { latitude: 40.7, longitude: -74.0 },
        status: 'healthy',
      });
      chain.addPlant({
        id: 'basil-1',
        name: 'Sweet Basil',
        species: 'Basil',
        variety: 'Genovese',
        generation: 1,
        propagationType: 'seed',
        dateAcquired: new Date().toISOString(),
        location: { latitude: 40.8, longitude: -73.9 },
        status: 'thriving',
      });
    });

    it('should find plant by ID', () => {
      const block = chain.findPlant('tomato-1');
      expect(block).toBeDefined();
      expect(block?.plant.name).toBe('Cherry Tomato');
    });

    it('should return undefined for non-existent plant', () => {
      const block = chain.findPlant('non-existent');
      expect(block).toBeUndefined();
    });
  });

  describe('Chain Validation', () => {
    it('should validate empty chain (genesis only)', () => {
      expect(chain.isValid()).toBe(true);
    });

    it('should validate chain with plants', () => {
      chain.addPlant({
        id: 'plant-1',
        name: 'Test Plant',
        species: 'Test',
        variety: 'Test',
        generation: 1,
        propagationType: 'original',
        dateAcquired: new Date().toISOString(),
        location: { latitude: 40.7, longitude: -74.0 },
        status: 'healthy',
      });
      expect(chain.isValid()).toBe(true);
    });
  });

  describe('Serialization', () => {
    beforeEach(() => {
      chain.addPlant({
        id: 'plant-1',
        name: 'Test Plant',
        species: 'Test',
        variety: 'Test',
        generation: 1,
        propagationType: 'original',
        dateAcquired: new Date().toISOString(),
        location: { latitude: 40.7, longitude: -74.0 },
        status: 'healthy',
      });
    });

    it('should export to JSON', () => {
      const json = chain.toJSON();
      expect(json).toBeDefined();
      expect(Array.isArray(json)).toBe(true);
    });

    it('should import from JSON', () => {
      const json = chain.toJSON();
      const restored = PlantChain.fromJSON(json);
      expect(restored.getChain().length).toBe(chain.getChain().length);
    });
  });
});
