package cli

import (
	"context"
	"fmt"
	"strconv"

	"github.com/cosmos/cosmos-sdk/client"
	"github.com/cosmos/cosmos-sdk/client/flags"
	"github.com/spf13/cobra"

	"github.com/UnUniFi/chain/x/nftbackedloan/types"
)

// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd(queryRoute string) *cobra.Command {

	cmd := &cobra.Command{
		Use:                        types.ModuleName,
		Short:                      fmt.Sprintf("Querying commands for the %s module", types.ModuleName),
		DisableFlagParsing:         true,
		SuggestionsMinimumDistance: 2,
		RunE:                       client.ValidateCmd,
	}

	cmd.AddCommand(
		CmdQueryParams(),
		CmdQueryListedNft(),
		CmdQueryListedNfts(),
		// CmdQueryLoans(),
		CmdQueryLoan(),
		CmdQueryNftBids(),
		CmdQueryBidderBids(),
		CmdQueryRewards(),
		CmdQueryListedClass(),
		CmdQueryLiquidation(),
	)

	return cmd
}

func CmdQueryParams() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "params",
		Short: "shows params",
		Args:  cobra.ExactArgs(0),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryParamsRequest{}

			res, err := queryClient.Params(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdQueryListedNft() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "nft-listing [class-id] [nft-id]",
		Short: "shows nft listing",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryListedNftRequest{
				ClassId: args[0],
				TokenId: args[1],
			}

			res, err := queryClient.ListedNft(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdQueryListedNfts() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "listed-nfts",
		Short: "shows listed nfts on the market",
		Args:  cobra.ExactArgs(0),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			owner, err := cmd.Flags().GetString(FlagOwner)
			if err != nil {
				return err
			}

			var params *types.QueryListedNftsRequest
			if owner != "" {
				params = &types.QueryListedNftsRequest{
					Owner: owner,
				}
			} else {
				params = &types.QueryListedNftsRequest{}
			}

			res, err := queryClient.ListedNfts(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	cmd.Flags().String(FlagOwner, "", "nft owner address")

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

// func CmdQueryLoans() *cobra.Command {
// 	cmd := &cobra.Command{
// 		Use:   "loans",
// 		Short: "shows loans",
// 		Args:  cobra.ExactArgs(0),
// 		RunE: func(cmd *cobra.Command, args []string) error {
// 			clientCtx := client.GetClientContextFromCmd(cmd)

// 			queryClient := types.NewQueryClient(clientCtx)

// 			params := &types.QueryLoansRequest{}

// 			res, err := queryClient.Loans(context.Background(), params)
// 			if err != nil {
// 				return err
// 			}

// 			return clientCtx.PrintProto(res)
// 		},
// 	}

// 	flags.AddQueryFlagsToCmd(cmd)

// 	return cmd
// }

func CmdQueryLoan() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "loan [class-id] [nft-id]",
		Short: "shows nft loan",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryLoanRequest{
				ClassId: args[0],
				TokenId: args[1],
			}

			res, err := queryClient.Loan(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdQueryNftBids() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "nft-bids [class-id] [nft-id]",
		Short: "shows nft bids",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryNftBidsRequest{
				ClassId: args[0],
				TokenId: args[1],
			}

			res, err := queryClient.NftBids(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdQueryBidderBids() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "bidder-bids [bidder]",
		Short: "shows bids by bidder",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryBidderBidsRequest{
				Bidder: args[0],
			}

			res, err := queryClient.BidderBids(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdQueryRewards() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "rewards [address]",
		Short: "shows rewards of an address",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryRewardsRequest{}

			res, err := queryClient.Rewards(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

func CmdQueryListedClass() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "listed-class [class-id] [nft-limit]",
		Short: "shows listed nft ids and uris in defined class-id",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)
			nftLimit, err := strconv.ParseInt(args[1], 10, 32)
			if err != nil {
				return err
			}
			req := types.QueryListedClassRequest{
				ClassId:  args[0],
				NftLimit: int32(nftLimit),
			}

			res, err := queryClient.ListedClass(context.Background(), &req)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}

// liquidation query command
func CmdQueryLiquidation() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "liquidation [class-id] [nft-id]",
		Short: "shows liquidation date",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			clientCtx := client.GetClientContextFromCmd(cmd)

			queryClient := types.NewQueryClient(clientCtx)

			params := &types.QueryLiquidationRequest{
				ClassId: args[0],
				TokenId: args[1],
			}

			res, err := queryClient.Liquidation(context.Background(), params)
			if err != nil {
				return err
			}

			return clientCtx.PrintProto(res)
		},
	}

	flags.AddQueryFlagsToCmd(cmd)

	return cmd
}
