import { ethers, upgrades, network } from "hardhat";
import { getNetworkConfig, getDeploymentConfig, validateEnvironment } from "./config/environments";
import { saveDeployment } from "./utils/deployment-tracker";
import { runPostDeploymentUpdates } from "./utils/post-deployment";

interface DeployConfig {
  owner: string;
  feeRecipient: string;
}

async function validateConfig(networkName: string): Promise<DeployConfig> {
  // Validate the environment
  validateEnvironment(networkName);

  // Get deployment configuration for this network
  const config = getDeploymentConfig(networkName);

  // Validate addresses
  if (!ethers.isAddress(config.owner)) {
    throw new Error(`Invalid OWNER_ADDRESS: ${config.owner}`);
  }

  if (config.feeRecipient !== "0x0000000000000000000000000000000000000000" && !ethers.isAddress(config.feeRecipient)) {
    throw new Error(`Invalid FEE_RECIPIENT: ${config.feeRecipient}`);
  }

  return config;
}

async function deployContract(config: DeployConfig, networkName: string) {
  const networkConfig = getNetworkConfig(networkName);

  console.log("๐Ÿš€ Deploying Cyberia (CAP) Token...");
  console.log(`๐ŸŒ Network: ${networkConfig.name} (Chain ID: ${networkConfig.chainId})`);
  console.log(`๐Ÿ“‹ Owner: ${config.owner}`);
  console.log(
    `๐Ÿ’ฐ Fee Recipient: ${config.feeRecipient === "0x0000000000000000000000000000000000000000" ? "Burn Mode" : config.feeRecipient}`
  );

  const [deployer] = await ethers.getSigners();
  console.log(`๐Ÿ”‘ Deployer: ${deployer.address}`);

  const balance = await ethers.provider.getBalance(deployer.address);
  console.log(`๐Ÿ’ต Deployer Balance: ${ethers.formatEther(balance)} ETH`);

  const contractFactory = await ethers.getContractFactory("CAPToken");

  console.log("\nโณ Deploying proxy contract...");
  const contract = await upgrades.deployProxy(contractFactory, [config.owner, config.feeRecipient], {
    kind: "uups",
    initializer: "initialize",
  });

  await contract.waitForDeployment();
  const proxyAddress = await contract.getAddress();

  // Get implementation address
  const implementationAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress);

  // Get deployment transaction details
  const deployTx = contract.deploymentTransaction();
  if (!deployTx) {
    throw new Error("Deployment transaction not found");
  }

  const receipt = await deployTx.wait(networkConfig.confirmations);
  if (!receipt) {
    throw new Error("Transaction receipt not found");
  }

  console.log(`โœ… CAP Token deployed successfully!`);
  console.log(`๐Ÿ“ Proxy Address: ${proxyAddress}`);
  console.log(`๐Ÿ“ Implementation Address: ${implementationAddress}`);
  console.log(`๐Ÿ“ Transaction Hash: ${receipt.hash}`);
  console.log(`โ›ฝ Gas Used: ${receipt.gasUsed.toString()}`);

  return {
    contract,
    proxyAddress,
    implementationAddress,
    txHash: receipt.hash,
    blockNumber: receipt.blockNumber,
    deployer: deployer.address,
  };
}

async function verifyDeployment(address: string, config: DeployConfig) {
  console.log("\n๐Ÿ” Verifying deployment...");

  const contract = await ethers.getContractAt("CAPToken", address);

  const name = await contract.name();
  const symbol = await contract.symbol();
  const totalSupply = await contract.totalSupply();
  const governance = await contract.governance();
  const feeRecipient = await contract.feeRecipient();

  console.log(`Token Name: ${name}`);
  console.log(`Token Symbol: ${symbol}`);
  console.log(`Total Supply: ${ethers.formatEther(totalSupply)} CAP`);
  console.log(`Governance: ${governance}`);
  console.log(`Fee Recipient: ${feeRecipient}`);

  // Validate deployment
  if (name !== "Cyberia") throw new Error("Invalid token name");
  if (symbol !== "CAP") throw new Error("Invalid token symbol");
  if (governance !== config.owner) throw new Error("Governance mismatch");
  if (feeRecipient !== config.feeRecipient) throw new Error("Fee recipient mismatch");

  console.log("โœ… Deployment verification passed!");
}

async function main() {
  try {
    const networkName = network.name;
    const networkConfig = getNetworkConfig(networkName);

    console.log("\nโ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—");
    console.log("โ•‘         CYBERIA (CAP) TOKEN DEPLOYMENT SCRIPT                 โ•‘");
    console.log("โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n");

    const config = await validateConfig(networkName);
    const deployment = await deployContract(config, networkName);
    await verifyDeployment(deployment.proxyAddress, config);

    // Save deployment record
    const deploymentRecord = {
      network: networkName,
      chainId: networkConfig.chainId,
      timestamp: new Date().toISOString(),
      proxyAddress: deployment.proxyAddress,
      implementationAddress: deployment.implementationAddress,
      deployer: deployment.deployer,
      owner: config.owner,
      feeRecipient: config.feeRecipient,
      txHash: deployment.txHash,
      blockNumber: deployment.blockNumber,
      verified: false,
    };

    saveDeployment(networkName, deploymentRecord);

    // Run post-deployment updates (auto-update .env, README, etc.)
    await runPostDeploymentUpdates(networkName, deploymentRecord);

    console.log("\n๐ŸŽ‰ Deployment completed successfully!");
    console.log(`\n๐Ÿ“ Next steps:`);

    if (networkConfig.isTestnet || networkName === "mainnet") {
      console.log(`1. Verify contract on Etherscan:`);
      console.log(`   npx hardhat verify --network ${networkName} ${deployment.proxyAddress}`);
      console.log(`\n2. View on Explorer:`);
      console.log(`   ${networkConfig.explorerUrl}/address/${deployment.proxyAddress}`);
    }

    console.log(`\n3. Update .env with deployed address:`);
    console.log(`   CAP_TOKEN_ADDRESS=${deployment.proxyAddress}`);
    console.log(`\n4. Configure pools and settings (if needed):`);
    console.log(`   npm run configure:${networkName}`);

    if (networkName === "mainnet") {
      console.log(`\nโš ๏ธ  IMPORTANT: This is a MAINNET deployment!`);
      console.log(`   - Save all addresses and transaction hashes securely`);
      console.log(`   - Transfer ownership to DAO governance when ready`);
      console.log(`   - Set up monitoring and alerts`);
    }
  } catch (error) {
    console.error("\nโŒ Deployment failed:", error);
    process.exitCode = 1;
  }
}

main();

Neighbours