package renderer

import (
	"fmt"
	"html/template"
	"net/http"

	"git.coopgo.io/coopgo-apps/parcoursmob/utils/icons"
	"git.coopgo.io/coopgo-apps/parcoursmob/utils/identification"
	"git.coopgo.io/coopgo-platform/emailing"
	"git.coopgo.io/coopgo-platform/groups-management/storage"
	"github.com/coreos/go-oidc"
	"github.com/spf13/viper"
)

type Renderer struct {
	TemplatesDir string
	GlobalConfig *viper.Viper
	ThemeConfig  *viper.Viper
	Mailer       *emailing.Mailer
}

func NewRenderer(global *viper.Viper, templates_dir string) *Renderer {
	theme := viper.New()
	theme.SetConfigName("config")
	theme.AddConfigPath(templates_dir)
	err := theme.ReadInConfig()
	if err != nil {
		panic(fmt.Errorf("fatal error config file: %w", err))
	}
	return &Renderer{
		TemplatesDir: templates_dir,
		GlobalConfig: global,
		ThemeConfig:  theme,
	}
}

func (renderer *Renderer) Render(name string, w http.ResponseWriter, r *http.Request, files []string, state RenderState) {

	genericFiles := renderer.ThemeConfig.GetStringSlice("views.generic.files")

	prefixed_files := []string{}
	for _, f := range genericFiles {
		prefixed_files = append(prefixed_files, renderer.templateFile(f))
	}
	for _, f := range files {
		prefixed_files = append(prefixed_files, renderer.templateFile(f))
	}

	w.WriteHeader(http.StatusOK)
	t := template.New(name).Funcs(
		template.FuncMap{
			"timeFrom":      TimeFrom,
			"timeFormat":    TimeFormat,
			"genderISO5218": GenderISO5218,
			"dict":          Dict,
			"json":          JSON,
			"rawjson":       RawJSON,
			"unescapeHTML":  UnescapeHTML,
			"walkingLength": WalkingLength,
			"divideFloat64": Divide[float64],
			"divideInt":     Divide[int],
		},
	)
	t = template.Must(t.ParseFiles(prefixed_files...))

	err := t.ExecuteTemplate(w, "main", state)
	if err != nil {
		fmt.Println(err)
	}
}

func (renderer *Renderer) RenderNoLayout(name string, w http.ResponseWriter, r *http.Request, files []string, state RenderState) {

	prefixed_files := []string{}
	for _, f := range files {
		prefixed_files = append(prefixed_files, renderer.templateFile(f))
	}

	w.WriteHeader(http.StatusOK)
	t := template.New(name).Funcs(
		template.FuncMap{
			"timeFrom":      TimeFrom,
			"timeFormat":    TimeFormat,
			"genderISO5218": GenderISO5218,
			"dict":          Dict,
			"json":          JSON,
			"rawjson":       RawJSON,
			"unsescapeHTML": UnescapeHTML,
			"divideFloat64": Divide[float64],
			"divideInt":     Divide[int],
		},
	)

	t = template.Must(t.ParseFiles(prefixed_files...))
	err := t.ExecuteTemplate(w, "main", state)
	if err != nil {
		fmt.Println(err)
	}
}

func (r *Renderer) templateFile(file string) string {
	return r.TemplatesDir + file
}

type RenderState struct {
	icons.IconSet
	LayoutState
	UserID     string
	UserClaims map[string]any
	Group      storage.Group
	Roles      any
	ViewState  any // This is a state specific to a given view
}

func NewState(r *http.Request, themeConfig *viper.Viper, menuState string) RenderState {
	iconset := themeConfig.GetStringMapString("icons.svg")

	// Get State elements from Request
	var userid string
	var claims map[string]any

	u := r.Context().Value(identification.IdtokenKey)
	if u != nil {
		if current_user_token, ok := u.(*oidc.IDToken); ok {
			userid = current_user_token.Subject
		}

		c := r.Context().Value(identification.ClaimsKey)
		if c != nil {
			if current_user_claims, ok := c.(map[string]any); ok {
				claims = current_user_claims
			}
		}

	}

	g := r.Context().Value(identification.GroupKey)
	if g == nil {
		return RenderState{
			IconSet:     icons.NewIconSet(iconset),
			LayoutState: LayoutState{},
		}
	}

	var roles map[string]any

	ro, ok := r.Context().Value(identification.RolesKey).(map[string]any)
	if ok {
		roles = ro
	}

	group := g.(storage.Group)

	modules := group.Data["modules"].(map[string]any)

	ls := LayoutState{
		AdministrationState: AdministrationState{
			Display: modules["administration"] != nil && modules["administration"].(bool),
			Active:  menuState == administrationMenu,
		},

		MenuItems: []MenuItem{
			{
				Title:  "Tableau de bord",
				Link:   "/app/",
				Active: menuState == dashboardMenu,
				Icon:   "hero:outline/home",
			},
		},
	}

	if modules["beneficiaries"] != nil && modules["beneficiaries"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Bénéficiaires",
			Link:   "/app/beneficiaries/",
			Active: menuState == beneficiariesMenu,
			Icon:   "hero:outline/user-group",
		})
	}

	if modules["journeys"] != nil && modules["journeys"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Déplacements",
			Link:   "/app/journeys/",
			Active: menuState == journeysMenu,
			Icon:   "hero:outline/map",
		})
	}

	if modules["vehicles"] != nil && modules["vehicles"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Véhicules partagés",
			Link:   "/app/vehicles/",
			Active: menuState == vehiclesMenu,
			Icon:   "tabler-icons:car",
		})
	}

	if modules["vehicles_management"] != nil && modules["vehicles_management"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Gestion des véhicules",
			Link:   "/app/vehicles-management/",
			Active: menuState == vehiclesmanagementMenu,
			Icon:   "hero:outline/briefcase",
		})
	}

	if modules["agenda"] != nil && modules["agenda"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Agenda dispositifs",
			Link:   "/app/agenda/",
			Active: menuState == agendaMenu,
			Icon:   "hero:outline/calendar",
		})
	}

	if modules["group_module"] != nil && modules["group_module"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Groupes / Communautés",
			Link:   "/app/group_module/",
			Active: menuState == groupMenu,
			Icon:   "hero:outline/group_module",
		})

	}

	if modules["support"] != nil && modules["support"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Support",
			Link:   "/app/support/",
			Active: menuState == commentMenu,
			Icon:   "hero:outline/support",
		})

	}

	if modules["directory"] != nil && modules["directory"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Répertoire solutions",
			Link:   "/app/directory/",
			Active: menuState == directoryMenu,
			Icon:   "hero:outline/document-text",
		})
	}
	if modules["conseillers"] != nil && modules["conseillers"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Conseillers",
			Link:   "/app/conseillers/",
			Active: menuState == membersMenu,
			Icon:   "hero:outline/user-group",
		})
	}
	if modules["solidarity_service"] != nil && modules["solidarity_service"].(bool) {
		ls.MenuItems = append(ls.MenuItems, MenuItem{
			Title:  "Transport solidaire",
			Link:   "/app/solidarity_service/",
			Active: menuState == solidarityserviceMenu,
			Icon:   "hero:outline/map",
		})
	}
	return RenderState{
		IconSet:     icons.NewIconSet(iconset),
		Group:       group,
		Roles:       roles,
		UserID:      userid,
		UserClaims:  claims,
		LayoutState: ls,
	}
}
