using System.ComponentModel.DataAnnotations;

namespace GerbilManagerWebAPI.Models
{
    /// <summary>
    /// A gerbil (Rennmaus). Pedigree is traversed via Litter → Father/Mother (no redundant
    /// parent FKs here). Genotype is one compact frozen-contract string (e.g.
    /// "Aa CC Dd EE GG Pp Spsp rere", "?" wildcards allowed); never SQL-filtered.
    /// </summary>
    public class Gerbil
    {
        [Key]
        public Guid Id { get; set; }
        public required string Name { get; set; }
        public Gender Gender { get; set; }
        public GerbilStatus Status { get; set; } = GerbilStatus.Active;

        // Birth litter (the litter this gerbil was born in).
        public Guid? LitterId { get; set; }
        public Litter? Litter { get; set; }

        // Contacts: Herkunft (origin) and Abnehmer (receiver, when given away).
        public Guid? OriginContactId { get; set; }
        public Contact? OriginContact { get; set; }
        public Guid? ReceiverContactId { get; set; }
        public Contact? ReceiverContact { get; set; }

        // Current home.
        public Guid? EnclosureId { get; set; }
        public Enclosure? Enclosure { get; set; }

        // Farbschlag.
        public Guid? ColorVarietyId { get; set; }
        public ColorVariety? ColorVariety { get; set; }

        public DateOnly? DateOfBirth { get; set; }
        public DateOnly? DateOfDeath { get; set; }
        public string? CauseOfDeath { get; set; }
        public DateOnly? GoHomeDate { get; set; }

        /// <summary>Compact genotype string (frozen GEN-1 contract). Null = not genotyped.</summary>
        public string? Genotype { get; set; }

        public string? Notes { get; set; }

        // Provenance (for the FEAT-8 spreadsheet import).
        public string? ImportSource { get; set; }
        public string? ExternalRef { get; set; }

        /// <summary>Raw import payload preserved verbatim (rawGenotype + unmappedTokens like
        /// the Uw locus / WFNZ markers) so nothing from the spreadsheets is lost. JSON text.</summary>
        public string? RawImportData { get; set; }

        /// <summary>Breeder/Herkunft (cattery/Zucht) as free text — set by the FEAT-8 import from
        /// the source Zucht (imported animals have no OriginContact). Gridify-filterable; the
        /// distinct values back the Tiere "Herkunft" dropdown (GET /gerbils/breeders).</summary>
        public string? OriginBreeder { get; set; }

        /// <summary>Separator-insensitive search key: Name lowercased with whitespace/.-_ stripped.
        /// Kept in sync automatically on save (see ApplicationContext.SaveChanges). Gridify-filterable
        /// so "clan kleine chaoten" matches "Clan-Kleine-Chaoten" (client strips separators too).</summary>
        public string? NameSearch { get; set; }

        /// <summary>FEAT-14: Charakterbogen trait labels (opaque to the backend — the
        /// {key,label} vocabulary lives frontend-side). Stored as a JSON text column.</summary>
        public List<string> CharacterTraits { get; set; } = new();

        /// <summary>FEAT-14: free-text character note; feeds the AI Verkaufstext.</summary>
        public string? CharacterNote { get; set; }

        /// <summary>GEN-3b: hearing/deaf phenotype flag (NOT a genotype locus — it's the
        /// downstream effect of high white load / Sp×Sls). null = not stated, true = deaf
        /// (dea/taub), false = hearing (Dea/hörend). Set by the FEAT-8 import from the
        /// after-spsp deafness annotation; see hive/agents/god/GENETIK-notation.md.</summary>
        public bool? IsDeaf { get; set; }

        /// <summary>Residency/ownership (ORIGIN, distinct from Abgabe location): true = part of
        /// the Clan-kleine-Chaoten Bestand, false = external pedigree ancestor (bred elsewhere).
        /// Rule (a) Zuchtname matches the Clan kennel, OR (b) it's a parent of a Clan offspring.
        /// Defaults true (manually-added animals are own stock); the FEAT-8 import classifies
        /// imported animals. See hive/agents/god/OWNERSHIP-residency.md. Gridify-filterable.</summary>
        public bool IsResident { get; set; } = true;
    }

    /// <summary>Shared normalisation for the separator-insensitive name search.</summary>
    public static class GerbilSearch
    {
        public static string Normalize(string? name)
        {
            if (string.IsNullOrEmpty(name)) return "";
            var chars = name.ToLowerInvariant()
                .Where(c => !char.IsWhiteSpace(c) && c != '-' && c != '.' && c != '_');
            return new string(chars.ToArray());
        }
    }
}
