package apperrorsx

import (
	"fmt"
	"net/http"
)

const (
	ModuleGeneral                  = "00"
	ModuleAuth                     = "01"
	ModulePIN                      = "02"
	ModuleHelicopter               = "03"
	ModuleHelicopterUsage          = "35"
	ModuleUser                     = "04"
	ModuleMasterData               = "05"
	ModuleDutyRoster               = "06"
	ModuleFlight                   = "07"
	ModuleContact                  = "08"
	ModuleMissionOps               = "09"
	ModuleFacility                 = "10"
	ModuleHospital                 = "11"
	ModuleFederalState             = "12"
	ModuleNationality              = "13"
	ModuleICAO                     = "14"
	ModuleLand                     = "15"
	ModuleBase                     = "16"
	ModuleHealthInsuranceCompanies = "17"
	ModuleVocation                 = "18"
	ModuleMedicine                 = "19"
	ModuleMasterSettings           = "20"
	ModuleFileManager              = "21"
	ModuleOPCData                  = "22"
	ModulePatientData              = "23"
	ModuleInsurancePatientData     = "24"
	ModuleRole                     = "25"
	ModuleFlightData               = "26"
	ModuleAirRescuerChecklist      = "27"
	ModuleBranding                 = "28"
	ModuleDUL                      = "29"
	ModuleTakeover                 = "30"
	ModuleFleetStatus              = "31"
	ModuleComplaint                = "32"
	ModuleEASARelease              = "33"
	ModuleMCF                      = "34"
	ModuleHelicopterUsageSync      = "35"
	ModuleFMReport                 = "36"
	ModuleAfterFlightInspection    = "37"
	ModuleActionSignoff            = "38"
)

// ContextKeyHTTPErrorDetail stores the original, non-sanitized error detail for
// request logging. HTTP response writers should sanitize the public payload but
// keep this local available for access logs.
const ContextKeyHTTPErrorDetail = "http_error_detail"

// ContextKeyHTTPErrorInternalDetail stores an internal-only, verbose error
// summary for request logging. Unlike ContextKeyHTTPErrorDetail, this is not
// meant for public response sanitizers.
const ContextKeyHTTPErrorInternalDetail = "http_error_internal_detail"

type Def struct {
	Status    int
	Code      string
	ErrorCode string
	Title     string
	Message   string
}

func Build(status int, moduleCode, caseCode, code, message string) Def {
	return BuildWithTitle(
		status,
		moduleCode,
		caseCode,
		code,
		titleForStatus(status),
		message,
	)
}

func BuildWithTitle(status int, moduleCode, caseCode, code, title, message string) Def {
	return Def{
		Status:    status,
		Code:      code,
		ErrorCode: fmt.Sprintf("%03d%s%s", status, moduleCode, caseCode),
		Title:     title,
		Message:   message,
	}
}

func titleForStatus(status int) string {
	switch status {
	case http.StatusAccepted:
		return "Accepted"
	case http.StatusBadRequest:
		return "Bad Request"
	case http.StatusUnauthorized:
		return "Unauthorized"
	case http.StatusLocked:
		return "Locked"
	case http.StatusForbidden:
		return "Forbidden"
	case http.StatusNotFound:
		return "Not found"
	case http.StatusConflict:
		return "Conflict"
	case http.StatusUnprocessableEntity:
		return "Validation error"
	case http.StatusTooManyRequests:
		return "Too many requests"
	default:
		return "Internal server error"
	}
}

func New(def Def) *AppError {
	return &AppError{
		Status:    def.Status,
		Code:      def.Code,
		ErrorCode: def.ErrorCode,
		Title:     def.Title,
		Message:   def.Message,
	}
}

func DefGeneral(status int, caseCode, code, message string) Def {
	return Build(status, ModuleGeneral, caseCode, code, message)
}

func DefGeneralWithTitle(status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, ModuleGeneral, caseCode, code, title, message)
}

func DefAuth(status int, caseCode, code, message string) Def {
	return Build(status, ModuleAuth, caseCode, code, message)
}

func DefPIN(status int, caseCode, code, message string) Def {
	return Build(status, ModulePIN, caseCode, code, message)
}

func DefPINWithTitle(status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, ModulePIN, caseCode, code, title, message)
}

func DefHelicopter(status int, caseCode, code, message string) Def {
	return Build(status, ModuleHelicopter, caseCode, code, message)
}

func DefHelicopterWithTitle(status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, ModuleHelicopter, caseCode, code, title, message)
}

func DefHelicopterUsage(status int, caseCode, code, message string) Def {
	return Build(status, ModuleHelicopterUsage, caseCode, code, message)
}

func DefHelicopterUsageWithTitle(status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, ModuleHelicopterUsage, caseCode, code, title, message)
}

func DefHelicopterUsageSync(status int, caseCode, code, message string) Def {
	return Build(status, ModuleHelicopterUsageSync, caseCode, code, message)
}

func DefHelicopterUsageSyncWithTitle(status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, ModuleHelicopterUsageSync, caseCode, code, title, message)
}

func DefFMReport(status int, caseCode, code, message string) Def {
	return Build(status, ModuleFMReport, caseCode, code, message)
}

func DefFMReportWithTitle(status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, ModuleFMReport, caseCode, code, title, message)
}

func DefByModule(moduleCode string, status int, caseCode, code, message string) Def {
	return Build(status, moduleCode, caseCode, code, message)
}

func DefByModuleWithTitle(moduleCode string, status int, caseCode, code, title, message string) Def {
	return BuildWithTitle(status, moduleCode, caseCode, code, title, message)
}
