package application

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

	mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
	solidarity_service "git.coopgo.io/sbouaram/solidarity-service/servers/grpc/proto"

	"github.com/google/uuid"
	"github.com/gorilla/mux"
	geojson "github.com/paulmach/go.geojson"
	"google.golang.org/protobuf/types/known/emptypb"
	"google.golang.org/protobuf/types/known/structpb"
	"google.golang.org/protobuf/types/known/timestamppb"
)

var BookingData Booking

type Booking struct {
	bookingData  solidarity_service.CreateBookingSolidarityRequest 
} 

func (h *ApplicationHandler) DriversJourney(w http.ResponseWriter, r *http.Request) {

	if r.Method == "GET" && r.FormValue("date") != ""{
				
		DepartureAddress := r.FormValue("departure");
		DestinationAddress := r.FormValue("destination");
		PickupDate := r.FormValue("date");
		
		layout := "2006-01-02T15:04"

		dateParsed, err := time.Parse(layout, PickupDate)

		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		var (
			departuregeo   *geojson.Feature
			destinationgeo *geojson.Feature
		)

		timestamp := timestamppb.New(dateParsed)

		if PickupDate != "" && DepartureAddress != "" && DestinationAddress != "" {
			// searched = true
	
			var err error
	
			departuregeo, err = geojson.UnmarshalFeature([]byte(DepartureAddress))
			if err != nil {
				fmt.Println(err)
				w.WriteHeader(http.StatusBadRequest)
				return
			}
	
			destinationgeo, err = geojson.UnmarshalFeature([]byte(DestinationAddress))
			if err != nil {
				fmt.Println(err)
				w.WriteHeader(http.StatusBadRequest)
				return
			}
		}

		request := solidarity_service.DriverJourneysRequest{
			DepartureDate: timestamp,
			Departure: &solidarity_service.Feature{
				Lat:     departuregeo.Geometry.Point[0],
				Long:    departuregeo.Geometry.Point[1],
				Address: DepartureAddress,
			},
		}

		drivers, err := h.services.GRPC.SolidarityService.DriverJourneys(context.TODO(), &request)

		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		BookingData.bookingData = solidarity_service.CreateBookingSolidarityRequest {
			Booking : &solidarity_service.BookingSolidarityRequest {
			
			DepartureAddress: &solidarity_service.Feature{
				Lat:     departuregeo.Geometry.Point[0],
				Long:    departuregeo.Geometry.Point[1],
				Address: DepartureAddress,
			},
			DestinationAddress: &solidarity_service.Feature{
				Lat:     destinationgeo.Geometry.Point[0],
				Long:    destinationgeo.Geometry.Point[1],
				Address: DepartureAddress,
			},
			PickupDate : timestamp,
		},
		}

		h.Renderer.SolidarityServiceListAvailableDrivers(w, r, drivers, &BookingData.bookingData)

	} else if r.Method == "POST" {

		vars := mux.Vars(r)
		beneficiaryID := vars["id"]

		driverId := r.FormValue("driver_id")
		id := uuid.New().String()

		BookingData.bookingData.Booking.DriverId = driverId
		BookingData.bookingData.Booking.PassengerId= beneficiaryID
		BookingData.bookingData.Booking.Id = id

		booking, err := h.services.GRPC.SolidarityService.CreateBookingSolidarity(context.TODO(), &BookingData.bookingData)

		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		h.Renderer.SolidarityServiceBooking(w, r, booking)

	}else {	

		h.Renderer.SolidarityService(w, r)
	}

}

func (h *ApplicationHandler) SolidarityService (w http.ResponseWriter, r *http.Request) {

	accounts, err := h.services.GRPC.SolidarityService.GetAllPassengers(context.TODO(), &emptypb.Empty{})
	drivers, err := h.services.GRPC.SolidarityService.GetAllDrivers(context.TODO(), &emptypb.Empty{})

	parcourmobAccounts, err := h.beneficiaries(r)
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(http.StatusBadRequest)
	}
	cacheid := uuid.NewString()
	h.cache.PutWithTTL(cacheid, accounts, 1*time.Hour)
	
	h.Renderer.BeneficiariesSolidarity(w, r, accounts, drivers, parcourmobAccounts, cacheid)
}

func (h *ApplicationHandler) CreateDriver (w http.ResponseWriter, r *http.Request) {

	if r.Method== "POST" {

		dataMap, err := parseBeneficiariesForm(r)
		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		data, err := structpb.NewValue(dataMap)
		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		userRequest := &mobilityaccounts.RegisterRequest{
			Account: &mobilityaccounts.Account{
				Namespace: "silvermobi",
				Data:      data.GetStructValue(),
			},
		}

		resp, err := h.services.GRPC.MobilityAccounts.Register(context.TODO(), userRequest)

		fmt.Println("resp : ", resp)
		address := resp.Account.Data.GetFields()["address"].GetStructValue();
		geometry := address.GetFields()["geometry"].GetStructValue();
		coordinates:= geometry.GetFields()["coordinates"].GetListValue();
		if len(coordinates.GetValues()) < 2{
			fmt.Printf("Erreur lors de la récupération des coordonées : %v", err)
			return
		}
		radiusStr := r.PostFormValue("radius")
		radius, err := strconv.Atoi(radiusStr)
		if err != nil {
			fmt.Printf("Erreur lors de la conversion de radius : %v", err)
			radius = 0
		}

		driverRequest := solidarity_service.DriverRegularAvailabilities {
			DriverRequest : &solidarity_service.DriverRequest {
				DriverAddress: &solidarity_service.Feature{
					Lat: coordinates.GetValues()[0].GetNumberValue(),
					Long: coordinates.GetValues()[1].GetNumberValue(),
					Address: "********",
				},
				DriverRadius: int32(radius),
				Driver: &solidarity_service.User{
					Id: resp.Account.Id,
					Alias: r.PostFormValue("alias"),
					FirstName: r.PostFormValue("first_name"),
					LastName: r.PostFormValue("last_name"),
					Grade: 1,
					Picture: "h.png",
					Gender: r.PostFormValue("gender"),
					VerifiedIdentity: true,      ///////// a Modifier !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
				},
				Preferences: &solidarity_service.Preferences{
					Smoking: false,
					Animals: false,
					Music: false,
					IsTalker: false,
					LuggageSize: 100,
				},
				Car: &solidarity_service.Car{
					Model: r.PostFormValue("model"),
					Brand: r.PostFormValue("brand"),
				},
			},
			DriverAvailabilities: []*solidarity_service.RegularAvailabilitySlot{
				{
				DayOfWeek: 4,
				StartTime: "10H00",
				EndTime: "11H00",
				},
			},
		}

		driverResponse, err := h.services.GRPC.SolidarityService.SetDriverRegularAvailabilities(context.TODO(), &driverRequest)
		if err != nil {
			fmt.Printf("erreur lors de la création du conducteur: ", err)
			radius = 0 
		}
		fmt.Println("driver: ", driverResponse)


	}
	
	h.Renderer.CreateDriver(w, r)
	
}
