# Presenters

## Overview

Presenters are responsible for transforming entity data into display-ready formats for views. They handle column definitions, data formatting, filtering, and search presentation, providing a clean separation between data models and view presentation logic.

## Purpose

Presenters serve several key functions:
- **Data Formatting** - Convert raw entity data into display formats
- **Column Management** - Define and manage table/list column configurations
- **Filter Integration** - Provide filter options for entity lists
- **Search Presentation** - Format entities for search results
- **View Abstraction** - Abstract presentation logic from controllers

## Structure

Each presenter typically follows this pattern:

```go
type PlantPresenter struct {
    Kit                         *kit.Kit
    PlantPrimaryColumnIllustrer *illustrers.PlantPrimaryColumnIllustrer
    PlantSearchIllustrer        *illustrers.PlantSearchIllustrer
    Presenter                   *presenter.Presenter
}
```

## Core Methods

### Data Column Formatting

```go
func (this *PlantPresenter) NameDataColumn(entity *mdl.Plant) goc.HTML {
    return this.Kit.Atoms.Cells.TextCell.TextCell(entity.Name)
}

func (this *PlantPresenter) CreatedAtDataColumn(entity *mdl.Plant) goc.HTML {
    return this.Kit.Atoms.Cells.TextCell.TextCell(entity.CreatedAt.Format("02/01/2006 15:04"))
}

func (this *PlantPresenter) HarvestedDataColumn(entity *mdl.Plant) goc.HTML {
    return this.Kit.Atoms.Cells.DecimalCell.DecimalCell(entity.Harvested)
}

func (this *PlantPresenter) PerennialDataColumn(entity *mdl.Plant) goc.HTML {
    return this.Kit.Atoms.Cells.BooleanCell.BooleanCell(entity.Perennial)
}
```

### Dynamic Column Access

```go
func (this *PlantPresenter) ColumnByKey(key string, entity *mdl.Plant) goc.HTML {
    switch key {
    case "name":
        return this.NameDataColumn(entity)
    case "created_at":
        return this.CreatedAtDataColumn(entity)
    case "harvested":
        return this.HarvestedDataColumn(entity)
    case "perennial":
        return this.PerennialDataColumn(entity)
    }
    return this.Kit.Organisms.Tables.Table.EmptyCellRow()
}
```

## Column Configuration

### Column Definition

```go
func (this *PlantPresenter) Columns(filter string) []*presenter.Column {
    var columns []*presenter.Column

    columns = append(columns, &presenter.Column{
        Key:   "name",
        Label: "Name",
        Kind:  "data",
        Main:  true,     // Show in main view
        Sub:   true,     // Show in sub view
    })

    columns = append(columns, &presenter.Column{
        Key:   "created_at",
        Label: "Created At",
        Kind:  "data",
        Main:  false,    // Hide in main view
        Sub:   false,    // Hide in sub view
    })

    return this.Presenter.FilteredColumns(columns, filter)
}
```

### Column Types

- **data** - Standard data columns
- **action** - Action/button columns
- **link** - Link/navigation columns
- **image** - Image display columns

## Search Integration

### Search Presentation

```go
func (this *PlantPresenter) Search(ctx context.Context, value *searcher.SearchValue, entity *mdl.Plant) goc.HTML {
    return this.PlantSearchIllustrer.Act(ctx, &illustrers.PlantSearchIllustrerMod{
        Entity: entity,
        Value:  value,
    })
}
```

### Primary Column Display

```go
func (this *PlantPresenter) PrimaryColumn(ctx context.Context, entity *mdl.Plant) goc.HTML {
    return this.PlantPrimaryColumnIllustrer.Act(ctx, &illustrers.PlantPrimaryColumnIllustrerMod{
        Entity: entity,
    })
}
```

## Filter Configuration

```go
func (this *PlantPresenter) Filters(ctx context.Context) []filter.Filter {
    filters := filter.Filters{}

    filters.AddIdFilter("id")
    filters.AddStringFilter("name")
    filters.AddStringFilter("exposition")
    filters.AddBooleanFilter("perennial")
    filters.AddIntegerFilter("size")

    return filters
}
```

## Integration with Views

Presenters are used by views to format data for display:

```go
// In a view template
func (this *PlantListView) renderTable(plants []*mdl.Plant) goc.HTML {
    var rows []goc.HTML

    for _, plant := range plants {
        row := this.Kit.Organisms.Tables.TableRow.TableRow(
            this.PlantPresenter.NameDataColumn(plant),
            this.PlantPresenter.PerennialDataColumn(plant),
            this.PlantPresenter.HarvestedDataColumn(plant),
        )
        rows = append(rows, row)
    }

    return this.Kit.Organisms.Tables.Table.Table(rows...)
}
```

## Cell Types

### Text Cells
```go
func (this *SomePresenter) TextColumn(entity *mdl.SomeEntity) goc.HTML {
    return this.Kit.Atoms.Cells.TextCell.TextCell(entity.TextValue)
}
```

### Numeric Cells
```go
func (this *SomePresenter) IntegerColumn(entity *mdl.SomeEntity) goc.HTML {
    return this.Kit.Atoms.Cells.IntegerCell.IntegerCell(entity.IntValue)
}

func (this *SomePresenter) DecimalColumn(entity *mdl.SomeEntity) goc.HTML {
    return this.Kit.Atoms.Cells.DecimalCell.DecimalCell(entity.DecimalValue)
}
```

### Boolean Cells
```go
func (this *SomePresenter) BooleanColumn(entity *mdl.SomeEntity) goc.HTML {
    return this.Kit.Atoms.Cells.BooleanCell.BooleanCell(entity.BoolValue)
}
```

### Date/Time Cells
```go
func (this *SomePresenter) DateColumn(entity *mdl.SomeEntity) goc.HTML {
    formatted := entity.Date.Format("02/01/2006")
    return this.Kit.Atoms.Cells.TextCell.TextCell(formatted)
}

func (this *SomePresenter) DateTimeColumn(entity *mdl.SomeEntity) goc.HTML {
    formatted := entity.DateTime.Format("02/01/2006 15:04")
    return this.Kit.Atoms.Cells.TextCell.TextCell(formatted)
}
```

## Custom Formatting

### Conditional Formatting

```go
func (this *PlantPresenter) StatusColumn(entity *mdl.Plant) goc.HTML {
    var cssClass string
    var text string

    if entity.Harvested > 0 {
        cssClass = "text-green-600"
        text = "Harvested"
    } else {
        cssClass = "text-yellow-600"
        text = "Growing"
    }

    return this.Kit.Component.Dc(cssClass, this.Kit.Component.Text(text))
}
```

### Complex Display Logic

```go
func (this *PlantPresenter) SizeDisplayColumn(entity *mdl.Plant) goc.HTML {
    switch {
    case entity.Size < 10:
        return this.Kit.Component.Text("Small")
    case entity.Size < 50:
        return this.Kit.Component.Text("Medium")
    default:
        return this.Kit.Component.Text("Large")
    }
}
```

## Best Practices

### Performance
- Use appropriate cell types for data formatting
- Avoid complex calculations in presentation methods
- Cache formatted values when possible

### Maintainability
- Keep presentation logic separate from business logic
- Use consistent naming conventions for column methods
- Group related columns logically

### Flexibility
- Support different column filter sets
- Allow for conditional column display
- Provide fallbacks for missing data

### Testing

```go
func TestPlantPresenter_NameDataColumn(t *testing.T) {
    presenter := setupPlantPresenter()
    plant := &mdl.Plant{Name: "Tomato"}

    result := presenter.NameDataColumn(plant)

    assert.Contains(t, string(result), "Tomato")
}

func TestPlantPresenter_Columns(t *testing.T) {
    presenter := setupPlantPresenter()

    columns := presenter.Columns("")

    assert.Greater(t, len(columns), 0)
    assert.Contains(t, getColumnKeys(columns), "name")
}
```

Presenters provide a clean, consistent way to transform entity data into formatted display elements while maintaining separation of concerns between data models and view presentation.