import { parseUnits, type Provider, type Signer, type Wallet } from 'ethers';
import { getAtiaContract } from "./contracts";
import { getAtiaBlessingDelegations } from './atia/graphql';


const PREFIX = `Atia's Blessing`;

export async function checkBlessings(wallet: Wallet, accessToken: string) {
  console.log(`⚙️ Starting ${PREFIX} daily pray`);
  const provider = 'provider' in wallet ? wallet.provider : undefined;
  const signer = 'provider' in wallet ? wallet : undefined;

  if (!provider) {
    console.error(`⚠️ ${PREFIX}: Provider is required for praying!`);
    return;
  }

  if (!signer) {
    console.error(`⚠️ ${PREFIX}: Wallet with signer is required for praying!`);
    return;
  }

  const address = await signer.getAddress();
  console.log("📋 Fetching delegations...");
  const delegations = await getAtiaBlessingDelegations(accessToken, address)

  // Extract unique delegatee addresses from delegations where current address is delegator
  const delegateeAddresses = new Set<string>();
  for (const delegation of delegations) {
    if (delegation.toAddress.toLowerCase() === address.toLowerCase()) {
      delegateeAddresses.add(delegation.fromAddress);
    }
  }

  // If no delegations limit found, pray for self too
  if (delegateeAddresses.size < 5) {
    delegateeAddresses.add(address);
    console.log("ℹ️ No delegations found, praying for self only");
  }

  const delegateesToPray = Array.from(delegateeAddresses);
  if (delegateesToPray.length > 5) {
    console.log(`❌ ${PREFIX}: Too many delegatees for prayer ${address.slice(-4)} (max: 5)`);
    return;
  }

  console.log(`🙏 Praying for ${delegateesToPray.length} delegatees...`);

  for (const delegatee of delegateesToPray) {
    await isActivated(delegatee, provider).then(async ({ status, streak }) => {
      if (status) {
        console.log(`⏱️ ${PREFIX}: Already activated for ${delegatee.slice(-4)} (streak: ${streak})`);
      } else {
        await activateStreak(signer, delegatee).then(({ status, streak }) => {
          if (!status) return;
          console.log(`✅ ${PREFIX}: Activated for ${delegatee.slice(-4)} (streak: ${streak})`);
        });
      }
    });
  }
}

export async function isActivated(address: string, provider: Provider) {
  const atiaContract = getAtiaContract(provider);
  const [currentStreakCount] = await atiaContract.getStreak(address);
  const [isLostStreak, hasPrayedToday] = await atiaContract.getActivationStatus(
    address,
    {
      gasPrice: parseUnits("20", "gwei"),
    }
  );

  return { status: hasPrayedToday, streak: Number(currentStreakCount) };
}

export async function activateStreak(signer: Signer | Provider, delegatee: string) {
  const atiaContract = getAtiaContract(signer);
  try {
    const [currentStreakCount] = await atiaContract.getStreak(
      delegatee,
      {
        gasPrice: parseUnits("20", "gwei"),
      }
    );
    const tx = await atiaContract.activateStreak(
      delegatee,
      {
        gasPrice: parseUnits("20", "gwei"),
      }
    );
    await tx.wait();
    return { status: true, streak: Number(currentStreakCount) + 1 };
  } catch (e: unknown) {
    console.error(e);
    console.error(`⚠️ ${PREFIX}: Failed to pray for ${delegatee.slice(-4)}`);
    return { status: false, streak: 0 };
  }
}

export async function getStreakDetails(address: string, provider: Provider) {
  const atiaContract = getAtiaContract(provider);
  const [currentStreakCount, lastActivated, longestStreakCount, lostStreakCount] = await atiaContract.getStreak(address);
  return {
    currentStreak: Number(currentStreakCount),
    lastActivated: Number(lastActivated),
    longestStreak: Number(longestStreakCount),
    lostStreaks: Number(lostStreakCount)
  };
}
