package models

import (
	"fmt"
	"os"

	"odoo-go/pkg/orm"
	"odoo-go/pkg/tools"
)

// Google Maps API client — only initialized if API key is set.
var mapsClient *tools.APIClient

func getClient() *tools.APIClient {
	if mapsClient != nil {
		return mapsClient
	}
	apiKey := os.Getenv("GOOGLE_MAPS_API_KEY")
	if apiKey == "" {
		return nil
	}
	mapsClient = tools.NewAPIClient("https://maps.googleapis.com", apiKey)
	return mapsClient
}

// initGoogleAddress extends res.partner with geocoding fields and methods.
func initGoogleAddress() {
	// Extend res.partner with lat/lng fields
	partner := orm.Registry.Get("res.partner")
	if partner != nil {
		partner.Extend(
			orm.Float("partner_latitude", orm.FieldOpts{String: "Geo Latitude"}),
			orm.Float("partner_longitude", orm.FieldOpts{String: "Geo Longitude"}),
		)

		// geo_localize: Geocode partner address → lat/lng
		// Calls Google Geocoding API: https://maps.googleapis.com/maps/api/geocode/json
		partner.RegisterMethod("geo_localize", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
			client := getClient()
			if client == nil {
				return nil, fmt.Errorf("google_address: GOOGLE_MAPS_API_KEY not configured")
			}

			env := rs.Env()
			for _, id := range rs.IDs() {
				// Read address fields
				var street, city, zip, country string
				env.Tx().QueryRow(env.Ctx(),
					`SELECT COALESCE(street,''), COALESCE(city,''), COALESCE(zip,''),
					 COALESCE((SELECT code FROM res_country WHERE id = p.country_id), '')
					 FROM res_partner p WHERE p.id = $1`, id,
				).Scan(&street, &city, &zip, &country)

				address := fmt.Sprintf("%s, %s %s, %s", street, zip, city, country)

				// Call Geocoding API
				var result GeocodingResponse
				err := client.GetJSON("/maps/api/geocode/json", map[string]string{
					"address": address,
				}, &result)
				if err != nil {
					return nil, fmt.Errorf("google_address: geocode failed: %w", err)
				}

				if result.Status == "OK" && len(result.Results) > 0 {
					loc := result.Results[0].Geometry.Location
					env.Tx().Exec(env.Ctx(),
						`UPDATE res_partner SET partner_latitude = $1, partner_longitude = $2 WHERE id = $3`,
						loc.Lat, loc.Lng, id)
				}
			}
			return true, nil
		})

		// address_autocomplete: Search for addresses via Google Places
		// Returns suggestions for autocomplete in the UI.
		partner.RegisterMethod("address_autocomplete", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
			client := getClient()
			if client == nil {
				return nil, fmt.Errorf("google_address: GOOGLE_MAPS_API_KEY not configured")
			}

			query := ""
			if len(args) > 0 {
				query, _ = args[0].(string)
			}
			if query == "" {
				return []interface{}{}, nil
			}

			var result AutocompleteResponse
			err := client.GetJSON("/maps/api/place/autocomplete/json", map[string]string{
				"input": query,
				"types": "address",
			}, &result)
			if err != nil {
				return nil, err
			}

			var suggestions []map[string]interface{}
			for _, p := range result.Predictions {
				suggestions = append(suggestions, map[string]interface{}{
					"description": p.Description,
					"place_id":    p.PlaceID,
				})
			}
			return suggestions, nil
		})

		// place_details: Get full address from place_id
		partner.RegisterMethod("place_details", func(rs *orm.Recordset, args ...interface{}) (interface{}, error) {
			client := getClient()
			if client == nil {
				return nil, fmt.Errorf("google_address: GOOGLE_MAPS_API_KEY not configured")
			}

			placeID := ""
			if len(args) > 0 {
				placeID, _ = args[0].(string)
			}
			if placeID == "" {
				return nil, fmt.Errorf("google_address: place_id required")
			}

			var result PlaceDetailsResponse
			err := client.GetJSON("/maps/api/place/details/json", map[string]string{
				"place_id": placeID,
				"fields":   "address_components,geometry,formatted_address",
			}, &result)
			if err != nil {
				return nil, err
			}

			if result.Status != "OK" {
				return nil, fmt.Errorf("google_address: place details failed: %s", result.Status)
			}

			// Parse address components
			address := map[string]interface{}{
				"formatted_address": result.Result.FormattedAddress,
				"latitude":          result.Result.Geometry.Location.Lat,
				"longitude":         result.Result.Geometry.Location.Lng,
			}

			for _, comp := range result.Result.AddressComponents {
				for _, t := range comp.Types {
					switch t {
					case "street_number":
						address["street_number"] = comp.LongName
					case "route":
						address["street"] = comp.LongName
					case "locality":
						address["city"] = comp.LongName
					case "postal_code":
						address["zip"] = comp.LongName
					case "country":
						address["country_code"] = comp.ShortName
						address["country"] = comp.LongName
					case "administrative_area_level_1":
						address["state"] = comp.LongName
					}
				}
			}

			return address, nil
		})
	}
}

// --- Google API Response Types ---

type GeocodingResponse struct {
	Status  string `json:"status"`
	Results []struct {
		FormattedAddress string `json:"formatted_address"`
		Geometry         struct {
			Location LatLng `json:"location"`
		} `json:"geometry"`
	} `json:"results"`
}

type LatLng struct {
	Lat float64 `json:"lat"`
	Lng float64 `json:"lng"`
}

type AutocompleteResponse struct {
	Status      string `json:"status"`
	Predictions []struct {
		Description string `json:"description"`
		PlaceID     string `json:"place_id"`
	} `json:"predictions"`
}

type PlaceDetailsResponse struct {
	Status string `json:"status"`
	Result struct {
		FormattedAddress  string `json:"formatted_address"`
		Geometry          struct {
			Location LatLng `json:"location"`
		} `json:"geometry"`
		AddressComponents []AddressComponent `json:"address_components"`
	} `json:"result"`
}

type AddressComponent struct {
	LongName  string   `json:"long_name"`
	ShortName string   `json:"short_name"`
	Types     []string `json:"types"`
}
