import { Interface, ZeroAddress } from 'ethers';
import { BestExecutionPlanner } from './best-execution-planner';
import { EncodedBridgeIntentPlan, EncodedPlannerRoutePlan, PlannerRequest } from './planner-v2-types';

const CHAIN_138 = 138;
const DEFAULT_ROUTER_V2_ADDRESS = '0xf1c93f54a5c2fc0d7766ccb0ad8f157dfb4c99ce';
const DEFAULT_INTENT_BRIDGE_COORDINATOR_V2_ADDRESS = '0x7d0022b7e8360172fd9c0bb6778113b7ea3674e7';

const routeInterface = new Interface([
  'function executeRoute((uint256 chainId,address inputToken,address outputToken,uint256 amountIn,uint256 minAmountOut,address recipient,uint256 deadline,(uint8 provider,address tokenIn,address tokenOut,uint8 amountSource,uint256 minAmountOut,address target,bytes providerData)[] legs) plan)',
]);

const intentInterface = new Interface([
  'function executeIntent((((uint256 chainId,address inputToken,address outputToken,uint256 amountIn,uint256 minAmountOut,address recipient,uint256 deadline,(uint8 provider,address tokenIn,address tokenOut,uint8 amountSource,uint256 minAmountOut,address target,bytes providerData)[] legs),bytes32 bridgeType,bytes bridgeData,(uint256 chainId,address inputToken,address outputToken,uint256 amountIn,uint256 minAmountOut,address recipient,uint256 deadline,(uint8 provider,address tokenIn,address tokenOut,uint8 amountSource,uint256 minAmountOut,address target,bytes providerData)[] legs),address recipient,uint256 deadline)) intent)',
]);

export interface InternalExecutionPlanV2Result {
  generatedAt: string;
  plannerResponse: Awaited<ReturnType<BestExecutionPlanner['plan']>>;
  execution?: {
    kind: 'route' | 'bridge-intent';
    contractAddress: string;
    functionName: string;
    signature: string;
    args: [EncodedPlannerRoutePlan] | [EncodedBridgeIntentPlan];
    encodedCalldata: string;
  };
  error?: string;
}

export class InternalExecutionPlanV2Builder {
  private planner: BestExecutionPlanner;

  constructor(planner = new BestExecutionPlanner()) {
    this.planner = planner;
  }

  async build(request: PlannerRequest): Promise<InternalExecutionPlanV2Result> {
    const plannerResponse = await this.planner.plan(request);
    const generatedAt = new Date().toISOString();

    if (plannerResponse.bridgeIntentPlan) {
      const contractAddress = (
        process.env.INTENT_BRIDGE_COORDINATOR_V2_ADDRESS ||
        (plannerResponse.sourceChainId === CHAIN_138 ? DEFAULT_INTENT_BRIDGE_COORDINATOR_V2_ADDRESS : '')
      ).trim().toLowerCase();
      if (!contractAddress) {
        return {
          generatedAt,
          plannerResponse,
          error: 'INTENT_BRIDGE_COORDINATOR_V2_ADDRESS is not configured',
        };
      }

      return {
        generatedAt,
        plannerResponse,
        execution: {
          kind: 'bridge-intent',
          contractAddress,
          functionName: 'executeIntent',
          signature: 'executeIntent(((uint256,address,address,uint256,uint256,address,uint256,(uint8,address,address,uint8,uint256,address,bytes)[]),bytes32,bytes,(uint256,address,address,uint256,uint256,address,uint256,(uint8,address,address,uint8,uint256,address,bytes)[]),address,uint256))',
          args: [plannerResponse.bridgeIntentPlan],
          encodedCalldata: intentInterface.encodeFunctionData('executeIntent', [plannerResponse.bridgeIntentPlan]),
        },
      };
    }

    if (plannerResponse.routePlan && plannerResponse.routePlan.legs.length > 0) {
      const contractAddress = (
        process.env.ENHANCED_SWAP_ROUTER_V2_ADDRESS ||
        (plannerResponse.sourceChainId === CHAIN_138 ? DEFAULT_ROUTER_V2_ADDRESS : '')
      ).trim().toLowerCase();
      if (!contractAddress) {
        return {
          generatedAt,
          plannerResponse,
          error: 'ENHANCED_SWAP_ROUTER_V2_ADDRESS is not configured',
        };
      }

      return {
        generatedAt,
        plannerResponse,
        execution: {
          kind: 'route',
          contractAddress,
          functionName: 'executeRoute',
          signature: 'executeRoute((uint256,address,address,uint256,uint256,address,uint256,(uint8,address,address,uint8,uint256,address,bytes)[]))',
          args: [plannerResponse.routePlan],
          encodedCalldata: routeInterface.encodeFunctionData('executeRoute', [plannerResponse.routePlan]),
        },
      };
    }

    return {
      generatedAt,
      plannerResponse,
      error: plannerResponse.decision === 'bridge-only'
        ? 'Bridge-only planner result does not require EnhancedSwapRouterV2 calldata'
        : plannerResponse.legs.length > 0
          ? 'Planner route includes one or more providers that are not yet executable through EnhancedSwapRouterV2'
          : 'No executable planner route found',
    };
  }
}
