package bridge

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"time"
)

const (
	squidAPIBase    = "https://v2.api.squidrouter.com"
	squidTimeout    = 10 * time.Second
	squidIntegrator = "explorer-bridge-aggregator"
)

var squidSupportedChains = map[int]bool{
	1: true, 10: true, 137: true, 42161: true, 8453: true,
	56: true, 43114: true, 100: true, 25: true, 250: true,
	324: true, 59144: true, 534352: true, 42220: true, 5000: true, 1111: true,
}

type squidReq struct {
	FromAddress string `json:"fromAddress"`
	FromChain   string `json:"fromChain"`
	FromToken   string `json:"fromToken"`
	FromAmount  string `json:"fromAmount"`
	ToChain     string `json:"toChain"`
	ToToken     string `json:"toToken"`
	ToAddress   string `json:"toAddress"`
	Slippage    int    `json:"slippage"`
}

type squidResp struct {
	Route *struct {
		Estimate *struct {
			ToAmount    string `json:"toAmount"`
			ToAmountMin string `json:"toAmountMin"`
		} `json:"estimate"`
	} `json:"route"`
}

type SquidProvider struct {
	apiBase string
	client  *http.Client
}

func NewSquidProvider() *SquidProvider {
	return &SquidProvider{apiBase: squidAPIBase, client: &http.Client{Timeout: squidTimeout}}
}

func (p *SquidProvider) Name() string { return "Squid" }

func (p *SquidProvider) SupportsRoute(fromChain, toChain int) bool {
	return squidSupportedChains[fromChain] && squidSupportedChains[toChain]
}

func (p *SquidProvider) GetQuote(ctx context.Context, req *BridgeRequest) (*BridgeQuote, error) {
	addr := req.Recipient
	if addr == "" {
		addr = "0x0000000000000000000000000000000000000000"
	}
	bodyReq := squidReq{
		FromAddress: addr, FromChain: strconv.Itoa(req.FromChain), FromToken: req.FromToken,
		FromAmount: req.Amount, ToChain: strconv.Itoa(req.ToChain), ToToken: req.ToToken,
		ToAddress: addr, Slippage: 1,
	}
	jsonBody, _ := json.Marshal(bodyReq)
	httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, p.apiBase+"/v2/route", bytes.NewReader(jsonBody))
	if err != nil {
		return nil, err
	}
	httpReq.Header.Set("Content-Type", "application/json")
	httpReq.Header.Set("x-integrator-id", squidIntegrator)
	resp, err := p.client.Do(httpReq)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, _ := io.ReadAll(resp.Body)
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("Squid API %d: %s", resp.StatusCode, string(body))
	}
	var r squidResp
	if err := json.Unmarshal(body, &r); err != nil {
		return nil, err
	}
	if r.Route == nil || r.Route.Estimate == nil {
		return nil, fmt.Errorf("Squid: no route")
	}
	toAmount := r.Route.Estimate.ToAmount
	if toAmount == "" {
		toAmount = r.Route.Estimate.ToAmountMin
	}
	if toAmount == "" {
		return nil, fmt.Errorf("Squid: no amount")
	}
	return &BridgeQuote{
		Provider: "Squid", FromChain: req.FromChain, ToChain: req.ToChain,
		FromAmount: req.Amount, ToAmount: toAmount, Fee: "0", EstimatedTime: "1-5 min",
		Route: []BridgeStep{{Provider: "Squid", From: strconv.Itoa(req.FromChain), To: strconv.Itoa(req.ToChain), Type: "bridge"}},
	}, nil
}
