package bridge

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

const symbiosisAPIBase = "https://api.symbiosis.finance/crosschain"
const symbiosisTimeout = 10 * time.Second

var symbiosisSupportedChains = 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,
}

type symbiosisReq struct {
	Amount        string `json:"amount"`
	TokenInChain  int    `json:"tokenInChainId"`
	TokenIn       string `json:"tokenIn"`
	TokenOutChain int    `json:"tokenOutChainId"`
	TokenOut      string `json:"tokenOut"`
	From          string `json:"from"`
	Slippage      int    `json:"slippage"`
}

type symbiosisResp struct {
	AmountOut    string `json:"amountOut"`
	AmountOutMin string `json:"amountOutMin"`
}

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

func NewSymbiosisProvider() *SymbiosisProvider {
	return &SymbiosisProvider{apiBase: symbiosisAPIBase, client: &http.Client{Timeout: symbiosisTimeout}}
}

func (p *SymbiosisProvider) Name() string { return "Symbiosis" }

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

func (p *SymbiosisProvider) GetQuote(ctx context.Context, req *BridgeRequest) (*BridgeQuote, error) {
	addr := req.Recipient
	if addr == "" {
		addr = "0x0000000000000000000000000000000000000000"
	}
	bodyReq := symbiosisReq{
		Amount: req.Amount, TokenInChain: req.FromChain, TokenIn: req.FromToken,
		TokenOutChain: req.ToChain, TokenOut: req.ToToken, From: addr, Slippage: 100,
	}
	jsonBody, _ := json.Marshal(bodyReq)
	httpReq, _ := http.NewRequestWithContext(ctx, http.MethodPost, p.apiBase+"/v2/quote", bytes.NewReader(jsonBody))
	httpReq.Header.Set("Content-Type", "application/json")
	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("Symbiosis API %d: %s", resp.StatusCode, string(body))
	}
	var r symbiosisResp
	if json.Unmarshal(body, &r) != nil {
		return nil, fmt.Errorf("Symbiosis parse error")
	}
	toAmount := r.AmountOut
	if toAmount == "" {
		toAmount = r.AmountOutMin
	}
	if toAmount == "" {
		return nil, fmt.Errorf("Symbiosis: no amount")
	}
	return &BridgeQuote{
		Provider: "Symbiosis", FromChain: req.FromChain, ToChain: req.ToChain,
		FromAmount: req.Amount, ToAmount: toAmount, Fee: "0", EstimatedTime: "1-5 min",
		Route: []BridgeStep{{Provider: "Symbiosis", From: strconv.Itoa(req.FromChain), To: strconv.Itoa(req.ToChain), Type: "bridge"}},
	}, nil
}
