package models

import (
	"errors"
	"strings"
	"time"
)

const (
	RoleReader = "Reader"
	RoleAdmin  = "Admin"
)

var AbuseCategories = []string{
	"physical",
	"psychological",
	"sexual",
	"economic",
	"material",
	"digital",
	"stalking",
	"threats",
	"honor_related",
}

var Genders = []string{"female", "male", "non_binary", "unknown"}
var Statuses = []string{"new", "open", "referred", "closed"}

var FaroeLocations = []string{
	"Akrar", "Argir", "Ánirnar", "Árnafjørður", "Bøur", "Dalur", "Depil", "Eiði",
	"Elduvík", "Fámjin", "Froðba", "Fuglafjørður", "Funningsfjørður", "Funningur",
	"Gásadalur", "Gjógv", "Glyvrar", "Gøtugjógv", "Haldórsvík", "Haraldssund",
	"Hattarvík", "Hellurnar", "Hestur", "Hov", "Hoyvík", "Hósvík", "Húsar",
	"Húsavík", "Hvalba", "Hvalvík", "Hvannasund", "Hvítanes", "Innan Glyvur",
	"Kaldbak", "Kaldbaksbotnur", "Kirkja", "Kirkjubøur", "Klaksvík", "Kolbeinagjógv",
	"Kollafjørður", "Koltur", "Kunoy", "Kvívík", "Lamba", "Lambareiði", "Langasandur",
	"Leirvík", "Leynar", "Ljósá", "Lopra", "Miðvágur", "Mikladalur", "Mjørkadalur",
	"Morskranes", "Múli", "Mykines", "Nes", "Nesvík", "Nólsoy", "Norðdepil",
	"Norðoyri", "Norðradalur", "Norðragøta", "Norðskáli", "Norðtoftir", "Oyndarfjørður",
	"Oyrarbakki", "Oyrareingir", "Oyri", "Porkeri", "Rituvík", "Runavík", "Saksun",
	"Saltangará", "Saltnes", "Sandavágur", "Sandur", "Sandvík", "Selatrað", "Signabøur",
	"Skarvanes", "Skála", "Skálafjørður/Skálabotnur", "Skálafjørður (Eysturkommuna)",
	"Skálavík", "Skipanes", "Skopun", "Skúgvoy", "Skælingur", "Stóra Dímun",
	"Strendur", "Streymnes", "Stykkið", "Sumba", "Sund", "Svínáir", "Svínoy",
	"Syðradalur (Kalsoy)", "Syðradalur (Streymoy)", "Syðrugøta", "Søldarfjørður",
	"Sørvágur", "Tjørnuvík", "Toftir", "Tórshavn", "Trongisvágur", "Trøllanes",
	"Tvøroyri", "Undir Gøtueiði", "Vatnsoyrar", "Vágur", "Válur", "Velbastaður",
	"Vestmanna", "Viðareiði", "Víkarbyrgi", "Æðuvík", "Ørðavík/Øravík", "Øravíkarlíð",
}

type Registration struct {
	ID           string `json:"id"`
	RegisteredAt string `json:"registered_at"`
	Gender       string `json:"gender"`
	Location     string `json:"location"`
	AbuseType    string `json:"abuse_type"`
	Status       string `json:"status"`
}

type RegistrationFilter struct {
	Location  string
	AbuseType string
	Gender    string
	Status    string
	Search    string
	From      time.Time
	To        time.Time
	HasFrom   bool
	HasTo     bool
	Limit     int
	Offset    int
}

func NormalizeRegistration(input *Registration) error {
	registeredAt := strings.TrimSpace(input.RegisteredAt)
	if registeredAt == "" {
		input.RegisteredAt = time.Now().UTC().Format(time.RFC3339)
	} else {
		parsed, err := ParseInputTime(registeredAt)
		if err != nil {
			return errors.New("registered_at must be RFC3339 or YYYY-MM-DD")
		}
		input.RegisteredAt = parsed.UTC().Format(time.RFC3339)
	}

	gender := strings.ToLower(strings.TrimSpace(input.Gender))
	if gender == "" {
		gender = "unknown"
	}
	if !ContainsFold(Genders, gender) {
		return errors.New("gender must be one of: female, male, non_binary, unknown")
	}
	input.Gender = gender

	location, ok := CanonicalLocation(input.Location)
	if !ok {
		return errors.New("location must be one of the allowed Faroese towns/villages")
	}
	input.Location = location

	abuseType := strings.ToLower(strings.TrimSpace(input.AbuseType))
	if !ContainsFold(AbuseCategories, abuseType) {
		return errors.New("abuse_type must be one of the allowed categories")
	}
	input.AbuseType = abuseType

	status := strings.ToLower(strings.TrimSpace(input.Status))
	if status == "" {
		status = "new"
	}
	if !ContainsFold(Statuses, status) {
		return errors.New("status must be one of: new, open, referred, closed")
	}
	input.Status = status

	return nil
}

func ParseInputTime(value string) (time.Time, error) {
	value = strings.TrimSpace(value)
	if parsed, err := time.Parse(time.RFC3339, value); err == nil {
		return parsed, nil
	}
	if parsed, err := time.Parse("2006-01-02", value); err == nil {
		return parsed, nil
	}
	return time.Time{}, errors.New("invalid time")
}

func CanonicalLocation(value string) (string, bool) {
	needle := strings.ToLower(strings.TrimSpace(value))
	for _, location := range FaroeLocations {
		if strings.ToLower(location) == needle {
			return location, true
		}
	}
	return "", false
}

func ContainsFold(values []string, needle string) bool {
	needle = strings.ToLower(strings.TrimSpace(needle))
	for _, value := range values {
		if strings.ToLower(strings.TrimSpace(value)) == needle {
			return true
		}
	}
	return false
}
