import { ContractFactory, ContractRunner, ethers, Interface } from 'ethers';
// import KAMI721CABI from '../abis/KAMI721C.json';
import { KAMI721C } from '../contracts/KAMI721C';
import compiledContract from '../abis/KAMI721C/KAMI721C.json';

/**
 * Factory class for deploying KAMI721C contracts
 */
export class KAMI721CFactory {
	private factory: ContractFactory;

	/**
	 * Creates a new instance of the KAMI721C factory
	 * @param signer A signer with deployment permissions
	 */
	constructor(signer: ContractRunner) {
		// Create factory with ABI and bytecode from the compiled contract
		this.factory = new ContractFactory(
			compiledContract.abi,
			compiledContract.bytecode, // The bytecode is already a string in the JSON
			signer
		);
	}

	/**
	 * Deploy a new KAMI721C contract
	 * @param usdcAddress The address of the USDC token contract
	 * @param name The name of the NFT collection
	 * @param symbol The symbol of the NFT collection
	 * @param baseURI The base URI for token metadata
	 * @param initialMintPrice The initial mint price in USDC (with 6 decimals)
	 * @param platformAddress The address that will receive platform commissions
	 * @param platformCommissionPercentage The platform commission percentage in basis points (e.g., 500 = 5%)
	 * @returns The deployed contract instance
	 */
	async deploy(
		usdcAddress: string,
		name: string,
		symbol: string,
		baseURI: string,
		initialMintPrice: bigint | string = 1000000n, // Default 1 USDC (6 decimals)
		platformAddress?: string,
		platformCommissionPercentage: number = 500 // Default 5%
	): Promise<KAMI721C> {
		// If platform address not provided, use the deployer's address
		if (!platformAddress) {
			// Get the signer's address
			if ('getAddress' in this.factory.runner!) {
				platformAddress = await (this.factory.runner as any).getAddress();
			} else {
				throw new Error('Platform address is required when deployer address cannot be determined');
			}
		}

		console.log('Deploying contract with parameters:', {
			usdcAddress,
			name,
			symbol,
			baseURI,
			initialMintPrice,
			platformAddress,
			platformCommissionPercentage,
		});

		try {
			console.log('Creating deployment transaction...');
			// Add gas limit to avoid out of gas errors
			const contract = await this.factory.deploy(
				usdcAddress,
				name,
				symbol,
				baseURI,
				initialMintPrice,
				platformAddress,
				platformCommissionPercentage,
				{ gasLimit: 5000000 } // Set a reasonable gas limit
			);

			console.log('Waiting for deployment transaction to be mined...');
			await contract.waitForDeployment();
			const address = await contract.getAddress();
			console.log('Contract deployed at address:', address);

			// Verify the contract was deployed successfully
			console.log('Verifying contract deployment...');
			const provider = contract.runner?.provider;
			if (!provider) {
				throw new Error('Contract deployment failed - no provider available');
			}
			const code = await provider.getCode(address);
			if (!code || code === '0x') {
				throw new Error('Contract deployment failed - no code at contract address');
			}
			console.log('Contract code verified successfully');

			const runner = contract.runner;
			if (!runner) {
				throw new Error('Contract deployment failed - no runner available');
			}
			return new KAMI721C(runner, address);
		} catch (error: any) {
			// Log more detailed error information
			console.error('Deployment failed:', {
				error: error.message,
				reason: error.reason,
				code: error.code,
				data: error.data,
				transaction: error.transaction,
			});
			throw error;
		}
	}
}
