package api

import (
	"fmt"

	"gordenko.dev/dima/fixme"
)

const (
	BadRequestBody               = "BAD_REQUEST_BODY"
	UnknownFunc                  = "UNKNOWN_FUNC"
	InternalError                = "INTERNAL_ERROR"
	NoSession                    = "NO_SESSION"
	TokenExpired                 = "TOKEN_EXPIRED"
	InvalidToken                 = "INVALID_TOKEN"
	MissingAuthorizationHeader   = "MISSING_AUTHORIZATION_HEADER"
	MalformedAuthorizationHeader = "MALFORMED_AUTHORIZATION_HEADER"
	//TokenNotValidYet      = "TOKEN_NOT_VALID_YET"
	///InvalidTokenSignature = "INVALID_TOKEN_SIGNATURE"
	//MalformedToken = "MALFORMED_TOKEN"
)

var (
	errorMessages = map[fixme.Code]string{
		UnknownFunc:                  "невідомий метод",
		InternalError:                "внутрішня помилка сервера",
		BadRequestBody:               "некоректне тіло запиту",
		TokenExpired:                 "токен прострочено",
		InvalidToken:                 "невірний токен",
		MissingAuthorizationHeader:   "Authorization header is missing",
		MalformedAuthorizationHeader: "Authorization header must be in format 'Bearer <token>'",
		//TokenNotValidYet:      "токен ще не активний",
		//InvalidTokenSignature: "підпис токена недійсний",
		//MalformedToken: "токен пошкоджено або зіпсовано",
	}
	fix = fixme.New(errorMessages)
)

type ErrorEnvelope struct {
	Error *Error `json:"error"`
}

type Leg struct {
	Field string `json:"field"`
	Idx   int    `json:"idx"`
}

type Error struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	Field   string `json:"field,omitempty"`
	List    string `json:"list,omitempty"`
	Idx     int    `json:"idx,omitempty"`
	Path    []Leg  `json:"path,omitempty"`
}

func (s Error) Error() string {
	var path string
	for _, leg := range s.Path {
		path += fmt.Sprintf(".%s[%d]", leg.Field, leg.Idx)
	}

	if s.Field != "" {
		// FIELD
		if s.Message != "" {
			// Looks like "E500: Unknown unit in .devices[1].units[0].unitID"
			return fmt.Sprintf("%s: %s in %s.%s", s.Code, s.Message, path, s.Field)
		} else {
			// Looks like "Error E500 in .devices[1].units[0].unitID"
			return fmt.Sprintf("Error %s in %s.%s", s.Code, path, s.Field)
		}
	} else if s.List != "" {
		// LIST
		if s.Message != "" {
			// Looks like "E500: Unknown unit in .devices[1].units[0].unitIDs[4]"
			return fmt.Sprintf("%s: %s in %s.%s[%d]", s.Code, s.Message, path, s.List, s.Idx)
		} else {
			return fmt.Sprintf("Error %s in %s.%s[%d]", s.Code, path, s.List, s.Idx)
		}
	} else {
		// ERROR
		if s.Message != "" {
			if path != "" {
				// Looks like "E500: Unknown unit in .devices[1].units[0]"
				return fmt.Sprintf("%s: %s in %s", s.Code, s.Message, path)
			} else {
				// Looks like "E500: Unknown unit"
				return fmt.Sprintf("%s: %s", s.Code, s.Message)
			}
		} else {
			if path != "" {
				// Looks like "Error E500 in .devices[1].units[0]"
				return fmt.Sprintf("Error %s in %s", s.Code, path)
			} else {
				// Looks like "Error E500"
				return fmt.Sprintf("Error %s", s.Code)
			}
		}
	}
}
