namespace TraceCad.Core.Model;

public sealed class SketchDocument
{
    public const int CurrentVersion = 1;

    public int Version { get; set; } = CurrentVersion;

    public string Units { get; set; } = "mm";

    public double Width { get; set; } = 210.0;

    public double Height { get; set; } = 297.0;

    public ReferenceImage? Reference { get; set; }

    public List<Layer> Layers { get; } = new();

    public List<Entity> Entities { get; } = new();

    public List<SketchConstraint> Constraints { get; } = new();

    public static SketchDocument CreateDefault()
    {
        var document = new SketchDocument();
        document.Layers.AddRange(new[]
        {
            Layer.Cut,
            Layer.Construction,
            Layer.Reference,
            Layer.Dimensions,
            Layer.Debug
        });
        return document;
    }

    public void AddEntity(Entity entity)
    {
        if (Entities.Any(existing => existing.Id == entity.Id))
        {
            throw new InvalidOperationException($"Entity '{entity.Id}' already exists.");
        }

        Entities.Add(entity);
    }

    public bool RemoveEntity(Guid id)
    {
        var index = Entities.FindIndex(entity => entity.Id == id);
        if (index < 0)
        {
            return false;
        }

        Entities.RemoveAt(index);
        Constraints.RemoveAll(constraint => constraint.EntityIds.Contains(id));
        return true;
    }

    public void ReplaceEntity(Entity replacement)
    {
        var index = Entities.FindIndex(entity => entity.Id == replacement.Id);
        if (index < 0)
        {
            throw new InvalidOperationException($"Entity '{replacement.Id}' does not exist.");
        }

        Entities[index] = replacement;
    }

    public void AddConstraint(SketchConstraint constraint)
    {
        if (Constraints.Any(existing => existing.Id == constraint.Id))
        {
            throw new InvalidOperationException($"Constraint '{constraint.Id}' already exists.");
        }

        Constraints.Add(constraint);
    }

    public bool RemoveConstraint(Guid id)
    {
        var index = Constraints.FindIndex(constraint => constraint.Id == id);
        if (index < 0)
        {
            return false;
        }

        Constraints.RemoveAt(index);
        return true;
    }

    public void ReplaceConstraint(SketchConstraint replacement)
    {
        var index = Constraints.FindIndex(constraint => constraint.Id == replacement.Id);
        if (index < 0)
        {
            throw new InvalidOperationException($"Constraint '{replacement.Id}' does not exist.");
        }

        Constraints[index] = replacement;
    }

    public Layer? FindLayer(string name) =>
        Layers.FirstOrDefault(layer => string.Equals(layer.Name, name, StringComparison.OrdinalIgnoreCase));
}
