package main

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

// free api for reverse geocoding based on IP
const revGeoURL = "http://ip-api.com/json/"

type Location struct {
	Lat     float64
	Lon     float64
	City    string
	State   string
	Country string
	Zipcode string
	// NWS specific location data
	// Station string
}

func NewLocation() *Location {
	return &Location{}
}

func (l *Location) UnmarshalJSON(b []byte) error {

	var aux struct {
		Lat     float64 `json:"lat,string"`
		Lon     float64 `json:"lon,string"`
		Address struct {
			City    string `json:"city"`
			State   string `json:"state"`
			Country string `json:"country"`
			Zipcode string `json:"postcode"`
		} `json:"address"`
	}

	if err := json.Unmarshal(b, &aux); err != nil {
		return err
	}

	// copy over values
	l.Lat = aux.Lat
	l.Lon = aux.Lon
	l.City = aux.Address.City
	l.State = aux.Address.State
	l.Country = aux.Address.Country
	l.Zipcode = aux.Address.Zipcode

	return nil
}

func SearchLocations(query string) ([]Location, error) {
	// url to perform location queries against
	//locations := []Location{}
	queryURL := fmt.Sprintf("https://nominatim.openstreetmap.org/search?q=%s&format=jsonv2&addressdetails=1", query)

	req, err := http.NewRequest(http.MethodGet, queryURL, nil)
	if err != nil {
		return []Location{}, err
	}

	req.Header.Set("User-Agent",
		"weather/0.1 (https://git.keegandeppe.com/kdeppe/weather; contact=19keegandeppe@gmail.com)")

	client := &http.Client{
		Timeout: 15 * time.Second,
	}

	resp, err := client.Do(req)

	if err != nil {
		return []Location{}, err
	}
	defer resp.Body.Close()

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return []Location{}, err
	}

	var locations []Location

	if err := json.Unmarshal(b, &locations); err != nil {
		panic(err)
	}

	// l := NewLocation()
	// l.UnmarshalJSON(b)

	fmt.Printf("%+v\n", locations)

	return locations, nil
}

// func (l *Location) getCoords() error {
//
// 	res, err := http.Get(revGeoURL)
//
// 	if err != nil {
// 		return err
// 	}
//
// 	body, err := io.ReadAll(res.Body)
// 	res.Body.Close()
// 	if res.StatusCode > 299 {
// 		errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
// 		return errors.New(errMsg)
// 	}
//
// 	if err != nil {
// 		return err
// 	}
//
// 	// unmarshall response into struct
// 	if err := json.Unmarshal(body, l); err != nil {
// 		return err
// 	}
//
// 	l.Found = true
//
// 	return nil
// }
//
// func (l *Location) getStation() error {
// 	// generate url based on coords
// 	url := fmt.Sprintf("https://api.weather.gov/points/%f,%f", l.Lat, l.Lon)
//
// 	res, err := http.Get(url)
//
// 	if err != nil {
// 		return err
// 	}
//
// 	body, err := io.ReadAll(res.Body)
// 	res.Body.Close()
// 	if res.StatusCode > 299 {
// 		errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
// 		return errors.New(errMsg)
// 	}
//
// 	if err != nil {
// 		return err
// 	}
//
// 	// send another request to station URL to find closest
// 	stationURL := gjson.Get(string(body), "properties.observationStations")
//
// 	res, err = http.Get(stationURL.String())
//
// 	if err != nil {
// 		return err
// 	}
//
// 	body, err = io.ReadAll(res.Body)
// 	res.Body.Close()
// 	if res.StatusCode > 299 {
// 		errMsg := fmt.Sprintf("Request failed with status code: %d\n", res.StatusCode)
// 		return errors.New(errMsg)
// 	}
//
// 	if err != nil {
// 		return err
// 	}
//
// 	station := gjson.Get(string(body), "features.0.properties.stationIdentifier")
//
// 	if station.String() == "" {
// 		return errors.New("Station not found")
// 	}
//
// 	l.Station = station.String()
//
// 	return nil
// }

// for debugging
func (l *Location) String() string {

	return fmt.Sprintf("%s, %s %s (%f, %f)", l.City, l.State, l.Zipcode, l.Lat, l.Lon)
}
