package customanalytics

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"strconv"
	"strings"

	"github.com/prebid/prebid-server/v3/analytics"

	"github.com/avct/uasurfer"
)

type CustomAnalyticsModule struct {
	cfg Configuration
}

type Configuration struct {
	endpoint string `json:"endpoint"`
}

func NewModule(endpoint string) (analytics.Module, error) {

	fmt.Println("endpoint", endpoint)
	if endpoint != "" {
		config := Configuration{
			endpoint: endpoint,
		}

		custom := CustomAnalyticsModule{
			cfg: config,
		}

		return &custom, nil
	} else {
		return nil, errors.New("Endpoint is missing")
	}

}

func (m *CustomAnalyticsModule) LogAuctionObject(auctionObject *analytics.AuctionObject) {

	fmt.Println("LogAuctionObject called")
	jsonreq, _ := json.Marshal(auctionObject.RequestWrapper)
	fmt.Println("Request", string(jsonreq))
	go func() {
		source := "s2s"
		currency := "USD"
		// Loop through all impressions in the request
		if auctionObject.RequestWrapper != nil {
			for _, imp := range auctionObject.RequestWrapper.Imp {
				var extData ExtData
				if err := json.Unmarshal(imp.Ext, &extData); err != nil {
					fmt.Println("Failed to parse imp.ext:", err)
					continue
				}
				fmt.Println("extdata", extData)

				var zoneid, deliverytype, format string
				var width, height int64

				if auctionObject.RequestWrapper.Site != nil {
					deliverytype = "site"
					zoneid = fmt.Sprint(extData.Zone_pId)
				} else if auctionObject.RequestWrapper.App != nil {
					deliverytype = "app"
					idValue, exists := extData.Prebid.Storedrequest["id"]
					if exists {
						fmt.Printf("stored request id %T\n", idValue)
						zone := strings.Split(idValue.(string), "_")
						zoneid = zone[0]
						fmt.Println("zoneid", zone[0])
					}
				}
				fmt.Println("zoneid", zoneid)

				// Determine ad format from request
				if imp.Banner != nil {
					format = "banner"
					width = imp.Banner.Format[0].W
					height = imp.Banner.Format[0].H

					fmt.Println("width", imp.Banner.Format[0].W)
					fmt.Println("height", imp.Banner.Format[0].H)

				} else if imp.Video != nil {
					format = "video"
					width = *imp.Video.W
					height = *imp.Video.H
					fmt.Println("width", *imp.Video.W)
					fmt.Println("height", *imp.Video.H)
				}

				fmt.Println("format", format)

				fmt.Println("useragent", auctionObject.RequestWrapper.Device.UA)
				useragent := auctionObject.RequestWrapper.Device.UA

				uaDetails := uasurfer.Parse(useragent)

				Browser := strings.TrimPrefix(uaDetails.Browser.Name.String(), "Browser")

				DeviceType := strings.TrimPrefix(uaDetails.DeviceType.String(), "Device")

				BrowserVersion := strconv.Itoa(uaDetails.Browser.Version.Major) + "." + strconv.Itoa(uaDetails.Browser.Version.Minor) + "." + strconv.Itoa(uaDetails.Browser.Version.Patch)

				Os := strings.TrimPrefix(uaDetails.OS.Name.String(), "OS")
				Osv := strconv.Itoa(uaDetails.OS.Version.Major) + "." + strconv.Itoa(uaDetails.OS.Version.Minor) + "." + strconv.Itoa(uaDetails.OS.Version.Patch)

				fmt.Println("Browser", Browser)
				fmt.Println("DeviceType", DeviceType)
				fmt.Println("BrowserVersion", BrowserVersion)
				fmt.Println("Os", Os)
				fmt.Println("Osv", Osv)

				// fmt.Println("Ip address", auctionObject.RequestWrapper.Device.IP)
				// if auctionObject.RequestWrapper.Device.IP != "" {
				// 	geoData, err := getGeoInfo(auctionObject.RequestWrapper.Device.IP)
				// 	if err != nil {
				// 		fmt.Println("Error fetching geo info:", err)
				// 	}

				// fmt.Println("Country:", geoData.Country)
				// fmt.Println("Country Code:", geoData.CountryCode)
				// fmt.Println("City:", geoData.City)
				// fmt.Println("Latitude:", geoData.Lat)
				// fmt.Println("Longitude:", geoData.Lon)
				// }

				for bidderName, _ := range extData.Prebid.Bidder {
					fmt.Printf("Bidder Name: %s\n", bidderName)
					_, err := http.Get(m.cfg.endpoint + "zoneid=" + zoneid + "&b=" + bidderName + "&source=" + source + "&bid=0&s=" + fmt.Sprint(width) + "x" + fmt.Sprint(height) + "&f=" + format + "&currency=" + currency + "&type=" + deliverytype + "&req=1")
					fmt.Println(m.cfg.endpoint + "zoneid=" + zoneid + "&b=" + bidderName + "&source=" + source + "&bid=0&s=" + fmt.Sprint(width) + "x" + fmt.Sprint(height) + "&f=" + format + "&currency=" + currency + "&type=" + deliverytype + "&req=1")
					if err != nil {
						fmt.Println("Error sending analytics data:", err)
					}
				}

				fmt.Println("29")
				// Loop through all seatbids in the response
				for _, seatBid := range auctionObject.Response.SeatBid {

					bidder := seatBid.Seat
					fmt.Println("bidder", seatBid.Seat)

					// Loop through all bids for this bidder
					for _, bid := range seatBid.Bid {
						if bid.W != 0 && bid.H != 0 {
							width = bid.W
							height = bid.H
						}
						fmt.Println("width res", width)
						fmt.Println("height res", height)

					}
					_, err := http.Get(m.cfg.endpoint + "zoneid=" + zoneid + "&b=" + bidder + "&source=" + source + "&bid=0&s=" + fmt.Sprint(width) + "x" + fmt.Sprint(height) + "&f=" + format + "&currency=" + currency + "&type=" + deliverytype + "&res=1")
					fmt.Println(m.cfg.endpoint + "zoneid=" + zoneid + "&b=" + bidder + "&source=" + source + "&bid=0&s=" + fmt.Sprint(width) + "x" + fmt.Sprint(height) + "&f=" + format + "&currency=" + currency + "&type=" + deliverytype + "&res=1")
					if err != nil {
						fmt.Println("Error sending analytics data:", err)
					}

				}

				var ext map[string]interface{}
				var exterrors map[string]interface{}
				var econtent map[string]interface{}
				// var extobj json.RawMessage
				// extobj = auctionObject.Response.Ext
				fmt.Println("extobj", string(auctionObject.Response.Ext))
				_ = json.Unmarshal(auctionObject.Response.Ext, &ext)
				// fmt.Println("ext", ext)
				fmt.Println("extobj tmaxrequest", ext["tmaxrequest"])
				fmt.Println("extobj responsetimemillies", ext["responsetimemillis"])
				fmt.Println("extobj errors", ext["errors"])

				if ext["errors"] != nil {
					exterrors = ext["errors"].(map[string]interface{})
					for bidderName, _ := range extData.Prebid.Bidder {
						fmt.Println("exterrors", exterrors[bidderName])
						if exterrors[bidderName] != nil {
							bidderErrors, _ := exterrors[bidderName].([]interface{})
							econtent = bidderErrors[0].(map[string]interface{})
							fmt.Println("code", econtent["code"])
							fmt.Println("msg", econtent["message"])
						}
					}
				}

			}
		}
	}()
}

func (m *CustomAnalyticsModule) LogAmpObject(ao *analytics.AmpObject) {
}

func (m *CustomAnalyticsModule) LogCookieSyncObject(cso *analytics.CookieSyncObject) {
}

func (m *CustomAnalyticsModule) LogNotificationEventObject(ne *analytics.NotificationEvent) {
}

func (m *CustomAnalyticsModule) LogSetUIDObject(so *analytics.SetUIDObject) {
}

func (m *CustomAnalyticsModule) LogVideoObject(vo *analytics.VideoObject) {
}

func (m *CustomAnalyticsModule) Shutdown() {
}

func getGeoInfo(ip string) (*GeoData, error) {
	url := fmt.Sprintf("http://ip-api.com/json/%s", ip)
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var geoData GeoData
	if err := json.NewDecoder(resp.Body).Decode(&geoData); err != nil {
		return nil, err
	}
	return &geoData, nil
}

type GeoData struct {
	Country     string  `json:"country"`
	CountryCode string  `json:"countryCode"`
	City        string  `json:"city"`
	Lat         float64 `json:"lat"`
	Lon         float64 `json:"lon"`
}

// Struct to store analytics data
type BidderAnalytics struct {
	BidderName    string
	Width         int
	Height        int
	ResponseCount int
	ZoneID        string
	Format        string
}

type ExtData struct {
	Prebid   Prebid `json:"prebid"`
	Zone_pId int64  `json:zone_pId`
}

type Prebid struct {
	Bidder        map[string]interface{} `json:"bidder"`
	Storedrequest map[string]interface{} `json:"storedrequest"`
}
