package main

import (
	"WM_CMS_SERVER/config"
	"WM_CMS_SERVER/frontendhandler"
	"WM_CMS_SERVER/mongodb"
	"WM_CMS_SERVER/util"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"
)

const (
	CONTENT_TYPE_INDEX    = 1
	CONTENT_ID_INDEX      = 2
	CONTENT_DATA_ID_INDEX = 3
)

type contextKey string

const userInfoKey contextKey = "userinfo"

type AuthUserInfo struct {
	ID          int
	Name        string
	DisplayName string
	Role        string
}

// func getBasicFunctionNames() []string {
// 	return []string{"users", "roles", "media"}
// }

// func isBasicFunction(target string) bool {
// 	funcNames := getBasicFunctionNames()
// 	found := false
// 	for _, funcName := range funcNames {
// 		if target == funcName {
// 			found = true
// 			break
// 		}
// 	}
// 	return found
// }

func InitBackendServerMux() *http.ServeMux {
	mux := http.NewServeMux()
	// 測試SSO資料寫入行內資料庫排程
	mux.HandleFunc("/testgoroutine", TestGoRoutine)
	mux.HandleFunc("/login", SSOLogin)

	mux.HandleFunc("/wmcms/hello", Hello)
	mux.HandleFunc("/wmcms/login", UserLogin)
	mux.HandleFunc("/wmcms/get_login_user", GetUserData)
	mux.HandleFunc("/wmcms/get_user_permission", GetUserPermission)

	mux.Handle("/wmcms/getdashboard", authMiddleware(http.HandlerFunc(GetDashboardSchema)))
	mux.Handle("/wmcms/schema/", authMiddleware(http.HandlerFunc(SchemaHandler)))

	mux.Handle("/wmcms/collection/", contentPermissionMiddleware(http.HandlerFunc(CollectionHandler)))
	mux.Handle("/wmcms/single/", contentPermissionMiddleware(http.HandlerFunc(SinglepageHandler)))
	mux.Handle("/wmcms/tag/", contentPermissionMiddleware(http.HandlerFunc(TagHandler)))

	// ContentType放行
	mux.Handle("/wmcms/allowcollectiondataupdate", supervisorCheckMiddleware(http.HandlerFunc(AllowCollectionDataUpdate)))
	mux.Handle("/wmcms/allowsingleupdate", supervisorCheckMiddleware(http.HandlerFunc(AllowSingleUpdateHandler)))
	mux.Handle("/wmcms/allowtagupdate", supervisorCheckMiddleware(http.HandlerFunc(AllowTagUpdateHandler)))

	mux.Handle("/wmcms/media", permissionCheckMiddleware("media", http.HandlerFunc(MediaHandler)))
	mux.Handle("/wmcms/mediaupload", permissionCheckMiddleware("media", http.HandlerFunc(MediaUploadFiles)))
	mux.Handle("/wmcms/mediaupdateall", supervisorCheckMiddleware(http.HandlerFunc(UpdateWebServerAllMedia)))

	mux.Handle("/wmcms/users/", permissionCheckMiddleware("users", http.HandlerFunc(UserHandler)))
	mux.Handle("/wmcms/roles/", permissionCheckMiddleware("roles", http.HandlerFunc(RoleHandler)))

	mux.Handle("/wmcms/getcontentlist", authMiddleware(http.HandlerFunc(ContentListHandler)))

	mux.Handle("/wmcms/getproduct/", authMiddleware(http.HandlerFunc(ProductHandler)))
	mux.Handle("/wmcms/productupdate/", authMiddleware(http.HandlerFunc(RequestProductUpdate)))
	mux.Handle("/wmcms/productupdatelog/", authMiddleware(http.HandlerFunc(GetProductUpdateLog)))
	mux.Handle("/wmcms/allowproductupdate", supervisorCheckMiddleware(http.HandlerFunc(AllowProductUpdate)))

	mux.Handle("/wmcms/productexport/", authMiddleware(http.HandlerFunc(ProductExportHandler)))
	mux.Handle("/wmcms/productmanualimport", authMiddleware(http.HandlerFunc(ImportProductManualHandler)))
	mux.Handle("/wmcms/productimportlog/", authMiddleware(http.HandlerFunc(GetProductImportLog)))
	mux.Handle("/wmcms/allowproductimport", supervisorCheckMiddleware(http.HandlerFunc(AllowProductImport)))

	mux.Handle("/api/", http.HandlerFunc(frontendhandler.ClientRequestHandler))

	//! Eason 寫的
	mux.Handle("/wmcms/companyimport", authMiddleware(http.HandlerFunc(ImportCompanyHandler)))
	mux.Handle("/wmcms/companyimportlog/", authMiddleware(http.HandlerFunc(GetCompanyImportLog)))
	mux.Handle("/wmcms/allowcompanyimport", supervisorCheckMiddleware(http.HandlerFunc(AllowCompanyImport)))

	mux.Handle("/wmcms/companyexport", authMiddleware(http.HandlerFunc(CompanyExportHandler)))
	mux.HandleFunc("/wmcms/updatefields", authMiddleware(http.HandlerFunc(UpdateFieldsHandler)).ServeHTTP)
	mux.HandleFunc("/wmcms/updateuserpermission", authMiddleware(http.HandlerFunc(UpdateUserPermissionHandler)).ServeHTTP)

	// AI 新增：用於測試目的的大量假資料生成接口
	mux.Handle("/wmcms/generate_test_data", authMiddleware(http.HandlerFunc(GenerateTestDataHandler)))

	return mux
}

// Middleware function to check for a valid bearer token
func authMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("[authMiddleware] Called")
		// Get the bearer token from the Authorization header
		strAuth := r.Header.Get("Authorization")
		token := strings.TrimPrefix(strAuth, "Bearer ")
		fmt.Println("[authMiddleware] token: ", token)
		// Validate the token
		claims, ok := validateToken(token)
		if !ok {
			http.Error(w, "Invalid token", http.StatusUnauthorized)
			return
		}

		userInfo := AuthUserInfo{
			Name:        claims["name"].(string),
			Role:        claims["role"].(string),
			DisplayName: claims["display_name"].(string),
		}

		ctx := context.WithValue(r.Context(), userInfoKey, userInfo)

		// If the token is valid, call the next handler in the chain
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// Middleware function to check for a valid bearer token and permission of the api
func permissionCheckMiddleware(requirePermission string, next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("[permissionMiddleware] Called")
		strAuth := r.Header.Get("Authorization")
		token := strings.TrimPrefix(strAuth, "Bearer ")
		fmt.Println("[permissionMiddleware] token: ", token)
		// Validate the token
		claims, ok := validateToken(token)
		if !ok {
			http.Error(w, "Invalid token", http.StatusUnauthorized)
			return
		}
		// 在這裡檢查使用者是否有權限進行該操作，如果沒有權限，直接回應 403 Forbidden
		// 如果有權限，則調用下一個 middleware 或處理函數
		str := claims["role"]
		if role, ok := str.(string); ok {
			fmt.Println("[permissionMiddleware] role: ", role)
			pass := isSuperUser(role)
			if !pass {
				switch r.Method {
				case "GET":
					pass = mongodb.HasPermission(role, "basic", requirePermission, "edit")
				case "POST":
					pass = mongodb.HasPermission(role, "basic", requirePermission, "edit")
				case "DELETE":
					pass = mongodb.HasPermission(role, "basic", requirePermission, "delete")
				}
			}

			if pass {
				userInfo := AuthUserInfo{
					Name:        claims["name"].(string),
					Role:        claims["role"].(string),
					DisplayName: claims["display_name"].(string),
				}

				ctx := context.WithValue(r.Context(), userInfoKey, userInfo)

				if r.Method == "POST" || r.Method == "DELETE" {
					log.Printf("Request to %s content. content:%s, user:%s\n", r.Method, requirePermission, userInfo.Name)
				}

				next.ServeHTTP(w, r.WithContext(ctx))

			} else {
				fmt.Println("[permissionMiddleware] No Permission. role:", role, " require:", requirePermission, " action:", r.Method)
				http.Error(w, "Forbidden", http.StatusForbidden)
				return
			}
		} else {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

	})
}

func contentPermissionMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("[contentPermissionMiddleware] Called")
		strAuth := r.Header.Get("Authorization")
		token := strings.TrimPrefix(strAuth, "Bearer ")
		fmt.Println("[contentPermissionMiddleware] token: ", token)
		// Validate the token
		claims, ok := validateToken(token)
		if !ok {
			http.Error(w, "Invalid token", http.StatusUnauthorized)
			return
		}
		// 在這裡檢查使用者是否有權限進行該操作，如果沒有權限，直接回應 403 Forbidden
		// 如果有權限，則調用下一個 middleware 或處理函數
		str := claims["role"]
		if role, ok := str.(string); ok {
			fmt.Println("[contentPermissionMiddleware] role: ", role)
			params := strings.Split(r.URL.Path, "/")[1:]
			fmt.Println("[contentPermissionMiddleware] r.URL.Path:", r.URL.Path)
			fmt.Println("[contentPermissionMiddleware] len(params) =", len(params), "params:", params)
			//如果沒帶足夠參數直接404
			if len(params) < 3 {
				http.NotFound(w, r)
				return
			}
			contentType := params[CONTENT_TYPE_INDEX]
			requirePermission := params[CONTENT_ID_INDEX]

			pass := isSuperUser(role)
			if !pass {
				switch r.Method {
				case "GET":
					pass = mongodb.HasPermission(role, contentType, requirePermission, "edit")
				case "POST":
					pass = mongodb.HasPermission(role, contentType, requirePermission, "edit")
				case "DELETE":
					pass = mongodb.HasPermission(role, contentType, requirePermission, "delete")
				}
			}

			if pass {
				userInfo := AuthUserInfo{
					Name:        claims["name"].(string),
					Role:        claims["role"].(string),
					DisplayName: claims["display_name"].(string),
				}

				ctx := context.WithValue(r.Context(), userInfoKey, userInfo)

				if r.Method == "POST" || r.Method == "DELETE" {
					log.Printf("Request to %s content. content:%s, user:%s\n", r.Method, requirePermission, userInfo.Name)
				}

				next.ServeHTTP(w, r.WithContext(ctx))
			} else {
				fmt.Println("[contentPermissionMiddleware] No Permission. role:", role, " require:", requirePermission, " action:", r.Method)
				http.Error(w, "Forbidden", http.StatusForbidden)
				return
			}
		} else {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

	})
}

func supervisorCheckMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("[supervisorCheckMiddleware] Called")
		strAuth := r.Header.Get("Authorization")
		token := strings.TrimPrefix(strAuth, "Bearer ")
		fmt.Println("[supervisorCheckMiddleware] token: ", token)
		// Validate the token
		claims, ok := validateToken(token)
		if !ok {
			http.Error(w, "Invalid token", http.StatusUnauthorized)
			return
		}
		// 在這裡檢查使用者是否有權限進行該操作，如果沒有權限，直接回應 403 Forbidden
		// 如果有權限，則調用下一個 middleware 或處理函數
		str := claims["role"]
		if role, ok := str.(string); ok {
			fmt.Println("[supervisorCheckMiddleware] role: ", role)
			pass := isSuperUser(role) || mongodb.IsSupervisor(role)
			if pass {
				userInfo := AuthUserInfo{
					Name:        claims["name"].(string),
					Role:        claims["role"].(string),
					DisplayName: claims["display_name"].(string),
				}

				ctx := context.WithValue(r.Context(), userInfoKey, userInfo)

				next.ServeHTTP(w, r.WithContext(ctx))

			} else {
				log.Println("[supervisorCheckMiddleware] No Permission. role:", role)
				http.Error(w, "Forbidden", http.StatusForbidden)
				return
			}
		} else {
			log.Println("[supervisorCheckMiddleware] role data error. role:", claims["role"])
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}

	})
}

func Hello(w http.ResponseWriter, r *http.Request) {
	// Set a custom header
	w.Header().Set("Content-Type", "application/json")

	// Write some JSON data to the response
	data := map[string]string{"message": "Hello, world!"}
	json.NewEncoder(w).Encode(data)
}

func TestGoRoutine(w http.ResponseWriter, r *http.Request) {
	fmt.Println("[TestGoRoutine] r: ", *r)

	ssoACInfoList, err := mongodb.CheckHRISDBData()
	if err != nil {
		fmt.Fprintln(w, err.Error())
	} else {
		yesterday := time.Now().AddDate(0, 0, -1)
		fileName := yesterday.Format("2006-01-02") + "_" + config.SSO_AC_INFO_LOG_FILE
		for _, ssoACInfo := range ssoACInfoList {
			// log.Printf("使用者 %s (%s) 已被停用", ssoACInfo.Username, ssoACInfo.DisplayName)
			ssoACInfoLog := &util.SSOACInfoLog{
				AppDate: yesterday.Format("20060102"),
				AppID:   config.APP_ID,
				// CompID:         ssoACInfo.CompID,
				// CompName:       ssoACInfo.CompName,
				CompID:         "SPHBK1",
				CompName:       "永豐銀行",
				DeptID:         ssoACInfo.BrID,
				DeptName:       ssoACInfo.BrName,
				EmpID:          ssoACInfo.Username,
				EmpName:        ssoACInfo.DisplayName,
				FunID:          "User",
				FunName:        "使用者管理",
				GrantType:      "系統授權",
				GrantDesc:      "",
				WorkStatus:     ssoACInfo.WorkStatus,
				WorkStatusDesc: ssoACInfo.WorkStatusDesc,
				GrantUserID:    "SYSTEM",
				GrantUserName:  "SYSTEM",
				Remark:         "",
			}
			util.WriteSSOACInfoLog(fileName, ssoACInfoLog)
		}
	}

	err1 := util.UpdateSSOACInfoLog()
	if err1 != nil {
		fmt.Fprintln(w, "UpdateSSOACInfoLog fail: ", err1.Error())
	}

	// err2 := util.UpdateSSOAPLoginLog()
	// if err2 != nil {
	// 	fmt.Fprintln(w, "UpdateSSOAPLoginLog fail: ", err2.Error())
	// }

	err3 := util.UpdateSSOAPLogControl()
	if err3 != nil {
		fmt.Fprintln(w, "UpdateSSOAPLogControl fail: ", err3.Error())
	}

	fmt.Fprintf(w, "Test Request Completed.")
}

func isSuperUser(role string) bool {
	if role == mongodb.SUPER_USER {
		fmt.Println("SUPER USER~~~!!!")
		return true
	}
	return false
}
