package application

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"sort"
	"strings"
	"time"

	groupsmanagement "git.coopgo.io/coopgo-platform/groups-management/grpcapi"
	groupstorage "git.coopgo.io/coopgo-platform/groups-management/storage"
	mobilityaccounts "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi"
	"github.com/google/uuid"
	"github.com/gorilla/mux"
	"google.golang.org/protobuf/types/known/structpb"
)

var Addres any

type BeneficiariesGroupForm struct {
	FirstName   string     `json:"first_name" validate:"required"`
	LastName    string     `json:"last_name" validate:"required"`
	Email       string     `json:"email" validate:"required,email"`
	Birthdate   *time.Time `json:"birthdate"`
	PhoneNumber string     `json:"phone_number" validate:"required,phoneNumber"`
	Address     any        `json:"address,omitempty"`
	Gender      string     `json:"gender"`
}

type GroupsModuleByName []groupstorage.Group

func (a GroupsModuleByName) Len() int { return len(a) }
func (a GroupsModuleByName) Less(i, j int) bool {
	return strings.Compare(a[i].Data["name"].(string), a[j].Data["name"].(string)) < 0
}
func (a GroupsModuleByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

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

	request := &groupsmanagement.GetGroupsRequest{
		Namespaces: []string{"parcoursmob_groups"},
	}

	resp, err := h.services.GRPC.GroupsManagement.GetGroups(context.TODO(), request)
	if err != nil {   
		fmt.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	var groups = []groupstorage.Group{}

	for _, group := range resp.Groups {
		g := group.ToStorageType()
		groups = append(groups, g)
	}

	sort.Sort(GroupsModuleByName(groups))

	h.Renderer.Groups(w, r, groups)
}

func (h *ApplicationHandler) CreateGroupModule(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		if r.PostFormValue("address") != "" {
			var a any
			json.Unmarshal([]byte(r.PostFormValue("address")), &a)

			Addres = a
		}
		r.ParseForm()

		if r.FormValue("name") == "" {

			fmt.Println("invalid name")
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		if r.FormValue("type") == "" {

			fmt.Println("invalid type")
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		groupid := uuid.NewString()

		dataMap := map[string]any{
			"name":        r.FormValue("name"),
			"type":        r.FormValue("type"),
			"description": r.FormValue("description"),
			"address":     Addres,
		}

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

		request_organization := &groupsmanagement.AddGroupRequest{
			Group: &groupsmanagement.Group{
				Id:        groupid,
				Namespace: "parcoursmob_groups",
				Data:      data.GetStructValue(),
			},
		}

		_, err = h.services.GRPC.GroupsManagement.AddGroup(context.TODO(), request_organization)
		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		http.Redirect(w, r, fmt.Sprintf("/app/group_module/groups/%s", groupid), http.StatusFound)
		return
	}
	group_types := h.config.GetStringSlice("modules.groups.group_types")
	h.Renderer.CreateGroupModule(w, r, group_types)
}

func filterAcccount(r *http.Request, a *mobilityaccounts.Account) bool {
	searchFilter, ok := r.URL.Query()["search"]

	if ok && len(searchFilter[0]) > 0 {
		name := a.Data.AsMap()["first_name"].(string) + " " + a.Data.AsMap()["last_name"].(string)
		if !strings.Contains(strings.ToLower(name), strings.ToLower(searchFilter[0])) {
			return false
		}
	}

	return true
}
func (h *ApplicationHandler) DisplayGroupModule(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	groupid := vars["groupid"]

	request := &groupsmanagement.GetGroupRequest{
		Id: groupid,
	}

	resp, err := h.services.GRPC.GroupsManagement.GetGroup(context.TODO(), request)
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	var accounts = []any{}

	requesst := &mobilityaccounts.GetAccountsBatchRequest{
		Accountids: resp.Group.Members,
	}

	ressp, _ := h.services.GRPC.MobilityAccounts.GetAccountsBatch(context.TODO(), requesst)
	// if err != nil {
	// 	return err
	// }
	for _, account := range ressp.Accounts {
		if filterAcccount(r, account) {
			a := account.ToStorageType()
			accounts = append(accounts, a)
		}
	}

	cacheid := uuid.NewString()
	h.cache.PutWithTTL(cacheid, accounts, 1*time.Hour)
	r.ParseForm()

	var beneficiary any

	searched := false

	// if r.Method == "POST" {
	if r.FormValue("beneficiaryid") != "" {
		// Handler form
		searched = true

		requestbeneficiary := &mobilityaccounts.GetAccountRequest{
			Id: r.FormValue("beneficiaryid"),
		}

		respbeneficiary, err := h.services.GRPC.MobilityAccounts.GetAccount(context.TODO(), requestbeneficiary)
		if err != nil {
			fmt.Println(err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		beneficiary = respbeneficiary.Account.ToStorageType()

		subscribe := &groupsmanagement.SubscribeRequest{
			Groupid:  resp.Group.ToStorageType().ID,
			Memberid: respbeneficiary.Account.Id,
		}

		_, err = h.services.GRPC.GroupsManagement.Subscribe(context.TODO(), subscribe)

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

		http.Redirect(w, r, fmt.Sprintf("/app/group_module/groups/%s", resp.Group.ToStorageType().ID), http.StatusFound)
		return
	}

	accountsBeneficaire, err := h.beneficiaries(r)
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	//h.Renderer.BeneficaireSearch(w, r, accounts, searched, beneficiary, resp.Group.ToStorageType())
	h.Renderer.DisplayGroupModule(w, r, resp.Group.ToStorageType().ID, accounts, cacheid, searched, beneficiary, resp.Group.ToStorageType(), accountsBeneficaire)
}
