/-
Copyright (c) 2025 Henrique Borges. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Davi Barreira, Henrique Borges
-/
import Vizagrams.Prim

/-!
# Graphical Marks for Vizagrams

This module implements the foundational concept of graphical marks as defined in the categorical
framework for data visualization. A graphical mark is fundamentally a tuple (A, θ_A) where:
- A is a type representing the mark's parameters
- θ_A : A → Array Prim is a function describing how to render the mark as primitives

## Conceptual Hierarchy

```
Prim (Primitive)     →  Array Prim  →  Visual Output
     ↑                       ↑
Mark (This module)    →  Array Prim  →  Visual Output
     ↑                       ↑
𝕋 Mark (Free Monad)  →  Array Prim  →  Visual Output
```

## Key Design Principles

1. **Type → Drawing Pipeline**: Any type can become drawable by implementing `MarkInterface`
2. **Ergonomic Composition**: Rich operator overloading (`+`, `*`) for intuitive syntax
3. **Automatic Coercion**: Seamless conversion between related types
4. **Universe Polymorphism**: Support for marks across different type universes

## Usage Examples

```lean
-- Basic mark creation and composition
let circle : Mark := myPrim                    -- Automatic coercion
let combined := mark1 + mark2                  -- Composition operator
let transformed := transform * mark            -- Transformation operator

-- All operations work seamlessly with type inference
```

## Theoretical Foundation

Following the categorical theory from "Data Visualization from a Category Theory Perspective":
- Marks are abstractions over Array Prim
- θ provides semantic interpretation: abstract mark → concrete primitives
- Composition forms a monoid structure
- Transformations preserve the categorical structure
-/
open LinearAlgebra
open GeometricPrimitive
open GraphicalPrimitive

-- Enable auto implicit for ergonomic type inference
set_option autoImplicit true

namespace GraphicalMark

-- Explicit universe declaration for polymorphic operations
universe u v

/-!
### Core Type Class: MarkInterface

The foundation of the mark system. Any type implementing this interface
can be rendered as visual primitives through the θ (theta) function.
-/

/--
**MarkInterface**: Defines how a type can be transformed into drawable primitives.

A type `α` can be drawn if there exists a function `θ : α → Array Prim`.
This follows the mathematical definition where a mark is a tuple (A, θ_A).

**Mathematical Interpretation:**
- A ∈ Type_u (the parameter space)
- θ_A : A → Array Prim (the rendering function)
- (A, θ_A) forms a graphical mark in our categorical framework

**Pipeline:** `α → Array Prim → Drawing`
-/
class MarkInterface (a : Type u) where
  /-- The theta function: transforms mark parameters into primitive arrays -/
  θ : a -> Array Prim

/-!
### Existential Mark Type

The `Mark` type provides a uniform interface for heterogeneous collections of marks.
It wraps any type implementing `MarkInterface`, enabling type-safe composition
while hiding the underlying type complexity.
-/

/--
**Mark**: An existential wrapper for any drawable type.

A Mark encapsulates:
- `T`: The underlying parameter type (hidden from users)
- `inst`: The MarkInterface instance providing θ
- `val`: The concrete parameter values

This enables heterogeneous mark collections while preserving type safety.

**Design Benefits:**
- **Type Erasure**: Users work with uniform `Mark` type
- **Extensibility**: New mark types integrate seamlessly
- **Composition**: All marks compose uniformly regardless of underlying type
-/
structure Mark where
  {T : Type u}                    -- Hidden parameter type
  [inst : MarkInterface T]        -- Rendering capability
  val : T                        -- Concrete parameter values

instance : Repr Mark where
  reprPrec m := reprPrec (m.inst.θ m.val)

/-!
### Universe Level Management

Support for combining marks defined at different universe levels.
Essential for compositional mark construction across type hierarchies.
-/

/--
**Mark.ulift**: Lift mark to higher universe level.

Enables combination of marks defined at different universe levels.
This is crucial for building complex diagrams that combine marks
from different abstraction levels.

**Category Theory Note:** This preserves the categorical structure
while enabling cross-universe composition.
-/
def Mark.ulift (x : Mark.{u}) : Mark.{max u v} where
  T := ULift x.T
  val := ULift.up x.val
  inst := {
    θ := fun (v : ULift x.T) => x.inst.θ (ULift.down v)
  }

/-!
### Core Mark Operations
-/

/--
**Mark.θ**: Extract primitive array from any mark.

This is the canonical rendering function that converts any Mark
into its visual representation as an Array Prim.

**Mathematical Interpretation:**
Projects the existential type back to the primitive space:
`∃T. (T, θ_T, val_T) → Array Prim`
-/
def Mark.θ : Mark → Array Prim := fun m => m.inst.θ m.val

/-!
### Fundamental Mark Instances

Basic types that can serve as marks. These provide the foundation
for more complex mark constructions.
-/

/--
**Nil**: Empty mark type representing visual void.

Analogous to the empty set ∅ in category theory.
Serves as the identity element for mark composition.
-/
inductive Nil : Type
  | mk : Nil

/-- **Nil Instance**: Renders as empty array (composition identity) -/
instance : MarkInterface Nil where
  θ _ := #[]

/-- **Unit Instance**: Alternative empty mark using built-in Unit type -/
instance : MarkInterface Unit where
  θ _ := #[]

/-- **Prim Instance**: Individual primitives are trivial marks -/
instance : MarkInterface Prim where
  θ p := #[p]

/-!
### Coercion System: Seamless Type Conversions

Rich coercion system enabling intuitive syntax. Users can write
natural code without explicit conversions between related types.

**Design Philosophy:** Make the common cases effortless while preserving type safety.
-/

/-- **Mark → Array Prim**: Extract primitives (every Mark can render) -/
instance : Coe Mark (Array Prim) where
  coe m := m.θ

/-- **Prim → Mark**: Lift primitive to mark level -/
instance : Coe Prim Mark where
  coe p := { val := p }

/-- **Nil → Mark**: Lift empty mark to uniform interface -/
instance : Coe Nil Mark where
  coe m := { val := m }

/-- **Unit → Mark**: Lift unit to mark level -/
instance : Coe Unit Mark where
  coe m := { val := m }

/-!
### Composition Operations: The `+` Operator

Rich composition system using the `+` operator for intuitive mark combination.
This implements the monoidal structure of mark composition.

**Mathematical Foundation:**
- Operation: `+` (composition)
- Identity: `Nil` (empty mark)
- Associativity: `(a + b) + c = a + (b + c)`
- Commutativity: Generally `a + b ≠ b + a` (order matters for rendering)
-/

/-- **Prim + Mark**: Prepend primitive to mark's primitives -/
instance : HAdd Prim Mark (Array Prim) where
  hAdd p1 p2 := #[p1] ++ p2.θ

/-- **Mark + Prim**: Append primitive to mark's primitives -/
instance : HAdd Mark Prim (Array Prim) where
  hAdd p1 p2 := p1.θ ++ #[p2]

/-- **Array Prim + Mark**: Prepend primitive array to mark -/
instance : HAdd (Array Prim) Mark (Array Prim) where
  hAdd p1 p2 := p1 ++ p2.θ

/-- **Mark + Mark**: Core composition operation -/
instance : HAdd Mark Mark (Array Prim) where
  hAdd p1 p2 := p1.θ ++ p2.θ

/-!
### Transformation Operations: The `*` Operator

Geometric and style transformation system using the `*` operator.
This implements the action of the transformation group on marks.

**Mathematical Foundation:**
- Geometric transformations form a group under composition
- Style transformations form a monoid under right-biased union
- The `*` operator applies these transformations to mark content

**Categorical Interpretation:**
- Transformations are morphisms in the category of geometric objects
- `*` implements the group action on the mark space
- Preserves the compositional structure of marks
-/

/-- **Mat2Vec2 * Mark**: Apply geometric transformation to mark -/
instance : HMul Mat2Vec2 Mark (Array Prim) where
  hMul g M := g * M.θ

/-- **Mark * Mat2Vec2**: Apply transformation (alternative syntax) -/
instance : HMul Mark Mat2Vec2 (Array Prim) where
  hMul M g := g * M.θ

/-!
### API Summary

**Core Functions:**
- `Mark.θ : Mark → Array Prim` - Extract primitives from any mark
- `Mark.ulift : Mark.{u} → Mark.{max u v}` - Universe level lifting

**Composition Operators:**
- `mark1 + mark2` - Combine two marks
- `prim + mark` / `mark + prim` - Mix primitives and marks
- `array + mark` - Combine primitive arrays with marks

**Transformation Operators:**
- `transform * mark` - Apply geometric/style transformation
- `mark * transform` - Alternative syntax for transformation

**Automatic Coercions:**
- `Prim → Mark` - Primitives automatically become marks
- `Nil → Mark` - Empty marks integrate seamlessly
- `Unit → Mark` - Unit type as empty mark
- `Mark → Array Prim` - Marks automatically render when needed

This design enables highly ergonomic syntax while maintaining mathematical rigor
and type safety throughout the system.
-/

end GraphicalMark
