package api

import (
	"net/http"
	"time"

	"github.com/aarondl/opt/null"
	"source.gleipnir.technology/Gleipnir/nidus-sync/db/models"
	"source.gleipnir.technology/Gleipnir/nidus-sync/h3utils"
	"source.gleipnir.technology/Gleipnir/nidus-sync/platform"
	"source.gleipnir.technology/Gleipnir/nidus-sync/platform/types"
	//"github.com/gorilla/mux"
	"github.com/rs/zerolog/log"
)

type H3Cell uint64

type Bounds struct {
	East  float64
	North float64
	South float64
	West  float64
}

func NewBounds() Bounds {
	return Bounds{
		East:  180,
		North: 180,
		South: -180,
		West:  -180,
	}
}

type NoteImagePayload struct {
	UUID      string     `json:"uuid"`
	Cell      H3Cell     `json:"cell"`
	Created   time.Time  `json:"created"`
	CreatorID int        `db:"creator_id"`
	Deleted   *time.Time `json:"deleted"`
	DeletorID *int32     `json:"deletor_id"`
	Version   int32      `json:"version"`
}

type NoteAudioPayload struct {
	UUID                    string                       `json:"uuid"`
	Breadcrumbs             []NoteAudioBreadcrumbPayload `json:"breadcrumbs"`
	Created                 time.Time                    `json:"created"`
	CreatorID               int                          `json:"creator_id"`
	Deleted                 *time.Time                   `json:"deleted"`
	DeletorID               *int32                       `json:"deletor_id"`
	Duration                float32                      `json:"duration"`
	Transcription           *string                      `json:"transcription"`
	TranscriptionUserEdited bool                         `json:"transcriptionUserEdited"`
	Version                 int32                        `json:"version"`
}

type ResponseDistrict struct {
	Agency  string `json:"agency"`
	Manager string `json:"manager"`
	Phone   string `json:"phone"`
	Website string `json:"website"`
}

type ResponseMosquitoSource struct {
	Access                  string                       `json:"access"`
	Active                  *bool                        `json:"active"`
	Comments                string                       `json:"comments"`
	Created                 string                       `json:"created"`
	Description             string                       `json:"description"`
	H3Cell                  int64                        `json:"h3cell"`
	ID                      string                       `json:"id"`
	LastInspectionDate      string                       `json:"last_inspection_date"`
	Habitat                 string                       `json:"habitat"`
	Inspections             []ResponseMosquitoInspection `json:"inspections"`
	Name                    string                       `json:"name"`
	NextActionDateScheduled string                       `json:"next_action_date_scheduled"`
	Treatments              []ResponseMosquitoTreatment  `json:"treatments"`
	UseType                 string                       `json:"use_type"`
	WaterOrigin             string                       `json:"water_origin"`
	Zone                    string                       `json:"zone"`
}

type NoteAudioBreadcrumbPayload struct {
	Cell             H3Cell    `json:"cell"`
	Created          time.Time `json:"created"`
	ManuallySelected bool      `json:"manuallySelected"`
}

type ResponseFieldseeker struct {
	MosquitoSources []ResponseMosquitoSource `json:"sources"`
	ServiceRequests []types.ServiceRequest   `json:"requests"`
	TrapData        []ResponseTrapData       `json:"traps"`
}

type ResponseClientIos struct {
	Fieldseeker ResponseFieldseeker `json:"fieldseeker"`
	Since       time.Time           `json:"since"`
}

func (i ResponseClientIos) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}

type ResponseMosquitoInspection struct {
	ActionTaken     string `json:"action_taken"`
	Comments        string `json:"comments"`
	Condition       string `json:"condition"`
	Created         string `json:"created"`
	EndDateTime     string `json:"end_date_time"`
	FieldTechnician string `json:"field_technician"`
	ID              string `json:"id"`
	LocationName    string `json:"location_name"`
	SiteCondition   string `json:"site_condition"`
}

func (rtd ResponseMosquitoInspection) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}
func NewResponseMosquitoInspection(i *models.FieldseekerMosquitoinspection) ResponseMosquitoInspection {
	return ResponseMosquitoInspection{
		ActionTaken:   i.Actiontaken.GetOr(""),
		Comments:      i.Comments.GetOr(""),
		Condition:     i.Sitecond.GetOr(""),
		Created:       i.Creationdate.MustGet().Format("2006-01-02T15:04:05.000Z"),
		ID:            i.Globalid.String(),
		LocationName:  i.Locationname.GetOr(""),
		SiteCondition: i.Sitecond.GetOr(""),
	}
}
func NewResponseMosquitoInspections(inspections models.FieldseekerMosquitoinspectionSlice) []ResponseMosquitoInspection {
	results := make([]ResponseMosquitoInspection, 0)
	for _, i := range inspections {
		results = append(results, NewResponseMosquitoInspection(i))
	}
	return results
}

func (rd ResponseDistrict) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}

func (rtd ResponseMosquitoSource) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}

func NewResponseMosquitoSource(ms platform.MosquitoSource) ResponseMosquitoSource {
	pl := ms.PointLocation
	h3cell, err := h3utils.ToCell(pl.H3cell.GetOr("0"))
	if err != nil {
		log.Warn().Err(err).Msg("Failed to convert h3 cell")
		h3cell = 0
	}
	return ResponseMosquitoSource{
		Active:                  toBool16(pl.Active),
		Access:                  pl.Accessdesc.GetOr(""),
		Comments:                pl.Comments.GetOr(""),
		Created:                 formatTime(pl.Creationdate),
		Description:             pl.Description.GetOr(""),
		H3Cell:                  int64(h3cell),
		ID:                      pl.Globalid.String(),
		LastInspectionDate:      formatTime(pl.Lastinspectdate),
		Habitat:                 pl.Habitat.GetOr(""),
		Inspections:             NewResponseMosquitoInspections(ms.Inspections),
		Name:                    pl.Name.GetOr(""),
		NextActionDateScheduled: formatTime(pl.Nextactiondatescheduled),
		Treatments:              NewResponseMosquitoTreatments(ms.Treatments),
		UseType:                 pl.Usetype.GetOr(""),
		WaterOrigin:             pl.Waterorigin.GetOr(""),
		Zone:                    pl.Zone.GetOr(""),
	}
}
func NewResponseMosquitoSources(sources []platform.MosquitoSource) []ResponseMosquitoSource {
	results := make([]ResponseMosquitoSource, 0)
	for _, i := range sources {
		results = append(results, NewResponseMosquitoSource(i))
	}
	return results
}

type ResponseMosquitoTreatment struct {
	Comments        string  `json:"comments"`
	Created         string  `json:"created"`
	EndDateTime     string  `json:"end_date_time"`
	FieldTechnician string  `json:"field_technician"`
	Habitat         string  `json:"habitat"`
	ID              string  `json:"id"`
	Product         string  `json:"product"`
	Quantity        float64 `json:"quantity"`
	QuantityUnit    string  `json:"quantity_unit"`
	SiteCondition   string  `json:"site_condition"`
	TreatAcres      float64 `json:"treat_acres"`
	TreatHectares   float64 `json:"treat_hectares"`
}

func (rtd ResponseMosquitoTreatment) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}
func NewResponseMosquitoTreatment(i *models.FieldseekerTreatment) ResponseMosquitoTreatment {
	return ResponseMosquitoTreatment{
		Comments:        i.Comments.GetOr(""),
		Created:         formatTime(i.Creationdate),
		FieldTechnician: i.Fieldtech.GetOr(""),
		Habitat:         i.Habitat.GetOr(""),
		ID:              i.Globalid.String(),
		Product:         i.Product.GetOr(""),
		Quantity:        i.Qty.GetOr(0),
		QuantityUnit:    i.Qtyunit.GetOr(""),
		SiteCondition:   i.Sitecond.GetOr(""),
		TreatAcres:      i.Treatacres.GetOr(0.0),
		TreatHectares:   i.Treathectares.GetOr(0.0),
	}
}
func NewResponseMosquitoTreatments(treatments models.FieldseekerTreatmentSlice) []ResponseMosquitoTreatment {
	results := make([]ResponseMosquitoTreatment, 0)
	for _, i := range treatments {
		results = append(results, NewResponseMosquitoTreatment(i))
	}
	return results
}

type ResponseNote struct {
	CategoryName string `json:"categoryName"`
	Content      string `json:"content"`

	H3Cell    int64  `json:"h3cell"`
	ID        string `json:"id"`
	Timestamp string `json:"timestamp"`
}

func (rtd ResponseNote) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}

func NewResponseServiceRequests(requests models.FieldseekerServicerequestSlice) []types.ServiceRequest {
	results := make([]types.ServiceRequest, 0)
	for _, i := range requests {
		results = append(results, types.ServiceRequestFromModel(i))
	}
	return results
}

type ResponseTrapData struct {
	Created     string `json:"created"`
	Description string `json:"description"`
	H3Cell      int64  `json:"h3cell"`
	ID          string `json:"id"`
	Name        string `json:"name"`
}

func (rtd ResponseTrapData) Render(w http.ResponseWriter, r *http.Request) error {
	return nil
}
func NewResponseTrapDatum(td *models.FieldseekerTraplocation) ResponseTrapData {
	return ResponseTrapData{
		Created:     formatTime(td.Creationdate),
		Description: td.Description.GetOr(""),
		ID:          td.Globalid.String(),
		//H3Cell:    td.H3Cell,
		Name: td.Name.GetOr(""),
	}
}
func NewResponseTrapData(data models.FieldseekerTraplocationSlice) []ResponseTrapData {
	results := make([]ResponseTrapData, 0)
	for _, i := range data {
		results = append(results, NewResponseTrapDatum(i))
	}
	return results
}

func toResponseFieldseeker(sync platform.FieldseekerRecordsSync) ResponseFieldseeker {
	return ResponseFieldseeker{
		MosquitoSources: NewResponseMosquitoSources(sync.MosquitoSources),
		ServiceRequests: NewResponseServiceRequests(sync.ServiceRequests),
		TrapData:        NewResponseTrapData(sync.TrapData),
	}
}

func formatTime(t null.Val[time.Time]) string {
	if t.IsNull() {
		return ""
	}
	v := t.MustGet()
	return v.Format("2006-01-02T15:04:05.000Z")
}

func toBool16(t null.Val[int16]) *bool {
	if t.IsNull() {
		return nil
	}
	val := t.MustGet()
	var b bool
	if val == 0 {
		b = false
	} else {
		b = true
	}
	return &b
}
