package model

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

	"github.com/go-resty/resty/v2"
	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

type DependencyLink struct {
	Parent    string `json:"parent"`
	Child     string `json:"child"`
	CallCount uint64 `json:"callCount"`
}

type DependencyResp struct {
	Data []*DependencyLink `json:"data"`
}

type TopoNode struct {
	Id    string `json:"id"`
	Label string `json:"label"`
}

type TopoEdge struct {
	Source string `json:"source"`
	Target string `json:"target"`
	Value  string `json:"value"`
}

type Topology struct {
	Nodes []*TopoNode `json:"nodes"`
	Edges []*TopoEdge `json:"edges"`
}

type GetDependencyResp struct {
	Data      []*DependencyLink `json:"data"`
	StartDate string            `json:"start_date"`
	EndDate   string            `json:"end_date"`
}

func GetTopology(ctx context.Context, addr string) (*Topology, error) {
	client := resty.NewWithClient(&http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)})
	resp, err := client.R().SetContext(ctx).Get(fmt.Sprintf("http://%s/api/dependencies?endTs=%d&lookback=604800000", addr, time.Now().Unix()*1000))
	if err != nil {
		return nil, err
	}
	dep := new(DependencyResp)
	err = json.Unmarshal(resp.Body(), dep)
	if err != nil {
		return nil, err
	}
	mapNode := make(map[string]struct{})
	nodes := make([]*TopoNode, 0, 10)
	edges := make([]*TopoEdge, 0, 10)
	for _, link := range dep.Data {
		if link.Parent == link.Child {
			continue
		}
		if _, ok := mapNode[link.Parent]; !ok {
			mapNode[link.Parent] = struct{}{}
			nodes = append(nodes, &TopoNode{Id: link.Parent, Label: link.Parent})
		}
		if _, ok := mapNode[link.Child]; !ok {
			mapNode[link.Child] = struct{}{}
			nodes = append(nodes, &TopoNode{Id: link.Child, Label: link.Child})
		}
		edges = append(edges, &TopoEdge{Source: link.Parent, Target: link.Child, Value: strconv.Itoa(int(link.CallCount))})
	}
	return &Topology{Nodes: nodes, Edges: edges}, nil
}

func GetDependency(ctx context.Context, addr string) (*GetDependencyResp, error) {
	client := resty.NewWithClient(&http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)})
	resp, err := client.R().SetContext(ctx).Get(fmt.Sprintf("http://%s/api/dependencies?endTs=%d&lookback=604800000", addr, time.Now().Unix()*1000))
	if err != nil {
		return nil, err
	}
	dep := new(DependencyResp)
	err = json.Unmarshal(resp.Body(), dep)
	if err != nil {
		return nil, err
	}
	data := make([]*DependencyLink, 0)
	for _, link := range dep.Data {
		if link.Parent == link.Child {
			continue
		}
		data = append(data, link)
	}
	date := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
	return &GetDependencyResp{StartDate: date, EndDate: date, Data: data}, nil
}
