package models

import (
	"encoding/json"
	"net/http"
	"strconv"
	"strings"

	"forge.grandlyon.com/gestion-des-assemblees/elections/internal/auth"
)

func (d *DataHandler) handleElection(w http.ResponseWriter, r *http.Request) {
	id, _ := strconv.Atoi(strings.TrimPrefix(r.URL.Path, "/api/Election/"))
	switch method := r.Method; method {
	case "GET":
		switch auth.GetLoggedUserTechnical(w, r).Role {
		case "ADMIN", "CAPTURER", "VISUALIZER":
			d.getElection(w, r, id)
		default:
			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
		}
	case "POST":
		switch auth.GetLoggedUserTechnical(w, r).Role {
		case "ADMIN":
			d.postElection(w, r)
		case "CAPTURER", "VISUALIZER":
			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
		default:
			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
		}

	case "PUT":
		switch auth.GetLoggedUserTechnical(w, r).Role {
		case "ADMIN":
			d.putElection(w, r, id)
		case "CAPTURER", "VISUALIZER":
			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
		default:
			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
		}
	case "DELETE":
		switch auth.GetLoggedUserTechnical(w, r).Role {
		case "ADMIN":
			d.deleteElection(w, r, id)
		case "CAPTURER", "VISUALIZER":
			http.Error(w, ErrorNotAuthorizeMethodOnRessource, http.StatusMethodNotAllowed)
		default:
			http.Error(w, ErrorRoleOfLoggedUser, http.StatusInternalServerError)
		}
	default:
		http.Error(w, "method not allowed", 400)
	}
}

func (d *DataHandler) getElection(w http.ResponseWriter, r *http.Request, id int) {
	if id != 0 {
		var o Election
		if err := d.db.Preload("Areas").First(&o, id).Error; err != nil {
			http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
			return
		}
		json.NewEncoder(w).Encode(o)
	} else {
		var o []Election
		d.db.Preload("Areas").Find(&o)
		json.NewEncoder(w).Encode(o)
	}
}

func (d *DataHandler) postElection(w http.ResponseWriter, r *http.Request) {
	var o Election
	err := json.NewDecoder(r.Body).Decode(&o)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	var elections []Election
	d.db.Find(&elections)
	for _, val := range elections {
		if o.Name == val.Name {
			http.Error(w, "Name Already exist.", 409)
			return
		}
	}

	d.db.Create(&o)
	d.db.Last(&o)
	json.NewEncoder(w).Encode(o)

}

func (d *DataHandler) putElection(w http.ResponseWriter, r *http.Request, id int) {
	var o Election
	if err := d.db.Preload("Areas").First(&o, id).Error; err != nil {
		http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
		return
	}
	var election Election
	err := json.NewDecoder(r.Body).Decode(&election)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	o.Name = election.Name
	o.BallotType = election.BallotType
	o.MapAreaFile = election.MapAreaFile
	o.MapSectionFile = election.MapSectionFile
	d.db.Save(&o)
	json.NewEncoder(w).Encode(o)

}

func (d *DataHandler) deleteElection(w http.ResponseWriter, r *http.Request, id int) {
	if id != 0 {
		var o Election
		if err := d.db.Preload("Areas").Preload("Rounds").First(&o, id).Error; err != nil {
			http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
			return
		}

		for _, area := range o.Areas {
			d.deleteArea(w, r, int(area.ID))
		}

		for _, round := range o.Rounds {
			d.deleteRound(w, r, int(round.ID))
		}

		d.db.Delete(&o)
	} else {
		http.Error(w, ErrorIDIsMissing, http.StatusNotFound)
	}
}