package cmd

import (
	"encoding/json"
	"fmt"
	"math/big"
	"os"

	"github.com/ethereum-optimism/optimism/op-node/rollup"
	"github.com/ethereum-optimism/superchain-registry/ops/flags"
	"github.com/ethereum/go-ethereum/common"
	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	"github.com/urfave/cli/v2"
)

var CheckRollupConfigCmd = cli.Command{
	Name:  "check-rollup-config",
	Flags: []cli.Flag{flags.RollupConfigFlag},
	Usage: "Sanity check rollup config (rollup.json) is reproducible",
	Action: func(ctx *cli.Context) error {
		// Ensure rollup config generated by op-node right now is equivalent to pre-existing
		// one used to create superchain config files. i.e. compare the following:
		//  1. op-node(superchain/configs/<l1-chain>/<l2-chain>.yaml) --> rollup.Config
		//  2. monorepo/op-node/rollup.json Unmarshal --> rollup.Config
		rollupConfigPath := ctx.String(flags.RollupConfigFlag.Name)

		fmt.Printf("Attempting to read from %s\n", rollupConfigPath)
		file, err := os.ReadFile(rollupConfigPath)
		if err != nil {
			return fmt.Errorf("failed to read from local rollup.json config file: %w", err)
		}
		var localRollupConfig *rollup.Config
		if err = json.Unmarshal(file, &localRollupConfig); err != nil {
			return fmt.Errorf("failed to unmarshal local rollup.json into rollup.Config struct: %w", err)
		}

		opNodeRollupConfig, err := rollup.LoadOPStackRollupConfig(localRollupConfig.L2ChainID.Uint64())
		if err != nil {
			return fmt.Errorf("op-node failed to generate rollup config: %w", err)
		}
		// Exclude this field from check since it gets populated by op-node after rollup.json is created
		localRollupConfig.ProtocolVersionsAddress = common.Address{}
		opNodeRollupConfig.ProtocolVersionsAddress = common.Address{}

		opts := cmp.Options{cmpopts.IgnoreUnexported(big.Int{})}
		if diff := cmp.Diff(localRollupConfig, opNodeRollupConfig, opts...); diff != "" {
			return fmt.Errorf("local rollup.json (-) does not match config generated by op-node (+): %s", diff)
		}

		fmt.Println("👌 Regenerated rollup config matches existing one")
		return nil
	},
}
