import { Injectable, Logger } from '@nestjs/common';
import { Web3Service } from './web3.service';
import { OnChainDocument } from '../interfaces/network-status.interface';

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

  private readonly documentChainAbi = [
    'function recordDocumentHash(string calldata requestId, string calldata documentId, string calldata hash, uint256 version) public returns (bytes32)',
    'function verifyDocumentHash(string calldata documentId, string calldata hash) public view returns (bool)',
    'function getDocumentHistory(string calldata documentId) public view returns (tuple(string documentId, string hash, uint256 version, uint256 timestamp, uint256 blockNumber)[])',
    'function getLatestDocumentHash(string calldata documentId) public view returns (string)',
  ];

  constructor(private web3Service: Web3Service) {}

  async recordDocumentHash(
    contractAddress: string,
    requestId: string,
    documentId: string,
    hash: string,
    version: number,
  ): Promise<string> {
    try {
      this.logger.debug(
        `Recording document hash: documentId=${documentId}, hash=${hash}, version=${version}`,
      );

      const contract = this.web3Service.getContract(contractAddress, this.documentChainAbi) as any;

      const tx = await contract.recordDocumentHash(requestId, documentId, hash, version);
      const receipt = await this.web3Service.sendTransaction(tx);

      this.logger.log(`Document hash recorded: ${receipt.hash}`);
      return receipt.hash!;
    } catch (error) {
      this.logger.error(`Failed to record document hash for ${documentId}`, error);
      throw error;
    }
  }

  async verifyDocumentHash(
    contractAddress: string,
    documentId: string,
    hash: string,
  ): Promise<boolean> {
    try {
      const contract = this.web3Service.getContract(contractAddress, this.documentChainAbi) as any;

      const isValid = await contract.verifyDocumentHash(documentId, hash);
      this.logger.debug(`Document hash verification: documentId=${documentId}, isValid=${isValid}`);
      return isValid;
    } catch (error) {
      this.logger.error(`Failed to verify document hash for ${documentId}`, error);
      return false;
    }
  }

  async getDocumentHistory(
    contractAddress: string,
    documentId: string,
  ): Promise<OnChainDocument[]> {
    try {
      const contract = this.web3Service.getContract(contractAddress, this.documentChainAbi) as any;

      const history = await contract.getDocumentHistory(documentId);

      return history.map((item: any) => ({
        documentId: item.documentId,
        hash: item.hash,
        version: Number(item.version),
        timestamp: new Date(Number(item.timestamp) * 1000),
        blockNumber: Number(item.blockNumber),
        transactionHash: '', // Would need to track separately
      }));
    } catch (error) {
      this.logger.error(`Failed to get document history for ${documentId}`, error);
      throw error;
    }
  }

  async getLatestDocumentHash(contractAddress: string, documentId: string): Promise<string> {
    try {
      const contract = this.web3Service.getContract(contractAddress, this.documentChainAbi) as any;

      return await contract.getLatestDocumentHash(documentId);
    } catch (error) {
      this.logger.error(`Failed to get latest document hash for ${documentId}`, error);
      throw error;
    }
  }
}
