package views

import (
	"testing"
	"time"

	"github.com/google/uuid"
	tablomodel "xtablo-backend/internal/tablos"
	taskmodel "xtablo-backend/internal/tasks"
)

func makeTask(status taskmodel.Status, isEtape bool) taskmodel.Record {
	return taskmodel.Record{
		ID:        uuid.New(),
		TabloID:   uuid.New(),
		OwnerID:   uuid.New(),
		Title:     "Task " + string(status),
		Status:    status,
		IsEtape:   isEtape,
		CreatedAt: time.Now().UTC(),
		UpdatedAt: time.Now().UTC(),
	}
}

func makeTablo() tablomodel.Record {
	return tablomodel.Record{
		ID:        uuid.New(),
		OwnerID:   uuid.New(),
		Name:      "Test Tablo",
		Color:     "#3B82F6",
		Status:    tablomodel.StatusTodo,
		CreatedAt: time.Now().UTC(),
		UpdatedAt: time.Now().UTC(),
	}
}

func TestComputeTabloProgress_Empty(t *testing.T) {
	got := computeTabloProgress([]taskmodel.Record{})
	if got != 0 {
		t.Fatalf("expected 0, got %d", got)
	}
}

func TestComputeTabloProgress_AllDone(t *testing.T) {
	tasks := []taskmodel.Record{
		makeTask(taskmodel.StatusDone, false),
		makeTask(taskmodel.StatusDone, false),
	}
	got := computeTabloProgress(tasks)
	if got != 100 {
		t.Fatalf("expected 100, got %d", got)
	}
}

func TestComputeTabloProgress_Half(t *testing.T) {
	tasks := []taskmodel.Record{
		makeTask(taskmodel.StatusDone, false),
		makeTask(taskmodel.StatusTodo, false),
	}
	got := computeTabloProgress(tasks)
	if got != 50 {
		t.Fatalf("expected 50, got %d", got)
	}
}

func TestComputeTabloProgress_EtapesIgnored(t *testing.T) {
	tasks := []taskmodel.Record{
		makeTask(taskmodel.StatusDone, false),
		// etape task — should be excluded from denominator and numerator
		makeTask(taskmodel.StatusTodo, true),
	}
	got := computeTabloProgress(tasks)
	if got != 100 {
		t.Fatalf("expected 100 (etape ignored), got %d", got)
	}
}

func TestNewTabloDetailViewModel_GroupsTasksByStatus(t *testing.T) {
	tablo := makeTablo()

	todoTask := makeTask(taskmodel.StatusTodo, false)
	todoTask.TabloID = tablo.ID

	inProgressTask := makeTask(taskmodel.StatusInProgress, false)
	inProgressTask.TabloID = tablo.ID

	doneTask := makeTask(taskmodel.StatusDone, false)
	doneTask.TabloID = tablo.ID

	tasks := []taskmodel.Record{todoTask, inProgressTask, doneTask}

	vm := NewTabloDetailViewModel(tablo, tasks, "Test User")

	if len(vm.Columns) != 4 {
		t.Fatalf("expected 4 columns, got %d", len(vm.Columns))
	}

	columnIDs := []string{"todo", "in_progress", "in_review", "done"}
	for i, col := range vm.Columns {
		if col.ID != columnIDs[i] {
			t.Errorf("column[%d]: expected ID %q, got %q", i, columnIDs[i], col.ID)
		}
	}

	// Column 0 = todo — 1 task
	if len(vm.Columns[0].Tasks) != 1 {
		t.Errorf("todo column: expected 1 task, got %d", len(vm.Columns[0].Tasks))
	}

	// Column 1 = in_progress — 1 task
	if len(vm.Columns[1].Tasks) != 1 {
		t.Errorf("in_progress column: expected 1 task, got %d", len(vm.Columns[1].Tasks))
	}

	// Column 2 = in_review — 0 tasks
	if len(vm.Columns[2].Tasks) != 0 {
		t.Errorf("in_review column: expected 0 tasks, got %d", len(vm.Columns[2].Tasks))
	}

	// Column 3 = done — 1 task
	if len(vm.Columns[3].Tasks) != 1 {
		t.Errorf("done column: expected 1 task, got %d", len(vm.Columns[3].Tasks))
	}
}

func TestNewTabloDetailViewModel_EtapesExcludedFromColumns(t *testing.T) {
	tablo := makeTablo()

	etapeTask := makeTask(taskmodel.StatusTodo, true)
	etapeTask.TabloID = tablo.ID

	regularTask := makeTask(taskmodel.StatusTodo, false)
	regularTask.TabloID = tablo.ID

	tasks := []taskmodel.Record{etapeTask, regularTask}
	vm := NewTabloDetailViewModel(tablo, tasks, "")

	// Only regular task in todo column
	if len(vm.Columns[0].Tasks) != 1 {
		t.Errorf("todo column: expected 1 task (etape excluded), got %d", len(vm.Columns[0].Tasks))
	}
}

func TestNewTabloDetailViewModel_EtapesPopulated(t *testing.T) {
	tablo := makeTablo()

	etape1 := taskmodel.Record{
		ID:        uuid.New(),
		TabloID:   tablo.ID,
		OwnerID:   tablo.OwnerID,
		Title:     "Etape One",
		Status:    taskmodel.StatusTodo,
		IsEtape:   true,
		CreatedAt: time.Now().UTC(),
		UpdatedAt: time.Now().UTC(),
	}

	etape2 := taskmodel.Record{
		ID:        uuid.New(),
		TabloID:   tablo.ID,
		OwnerID:   tablo.OwnerID,
		Title:     "Etape Two",
		Status:    taskmodel.StatusTodo,
		IsEtape:   true,
		CreatedAt: time.Now().UTC(),
		UpdatedAt: time.Now().UTC(),
	}

	child1 := taskmodel.Record{
		ID:           uuid.New(),
		TabloID:      tablo.ID,
		OwnerID:      tablo.OwnerID,
		Title:        "Child A",
		Status:       taskmodel.StatusTodo,
		IsEtape:      false,
		ParentTaskID: &etape1.ID,
		CreatedAt:    time.Now().UTC(),
		UpdatedAt:    time.Now().UTC(),
	}

	child2 := taskmodel.Record{
		ID:           uuid.New(),
		TabloID:      tablo.ID,
		OwnerID:      tablo.OwnerID,
		Title:        "Child B",
		Status:       taskmodel.StatusInProgress,
		IsEtape:      false,
		ParentTaskID: &etape1.ID,
		CreatedAt:    time.Now().UTC(),
		UpdatedAt:    time.Now().UTC(),
	}

	orphan := taskmodel.Record{
		ID:        uuid.New(),
		TabloID:   tablo.ID,
		OwnerID:   tablo.OwnerID,
		Title:     "No Etape",
		Status:    taskmodel.StatusTodo,
		IsEtape:   false,
		CreatedAt: time.Now().UTC(),
		UpdatedAt: time.Now().UTC(),
	}

	tasks := []taskmodel.Record{etape1, etape2, child1, child2, orphan}
	vm := NewTabloDetailViewModel(tablo, tasks, "")

	if len(vm.Etapes) != 2 {
		t.Fatalf("expected 2 etapes, got %d", len(vm.Etapes))
	}

	// Find etape1 in the Etapes slice
	var foundEtape1 *TabloDetailEtapeView
	for i := range vm.Etapes {
		if vm.Etapes[i].ID == etape1.ID.String() {
			foundEtape1 = &vm.Etapes[i]
			break
		}
	}

	if foundEtape1 == nil {
		t.Fatal("etape1 not found in vm.Etapes")
	}

	if foundEtape1.TaskCount != 2 {
		t.Errorf("etape1: expected TaskCount=2, got %d", foundEtape1.TaskCount)
	}

	// Find etape2 — should have TaskCount=0
	var foundEtape2 *TabloDetailEtapeView
	for i := range vm.Etapes {
		if vm.Etapes[i].ID == etape2.ID.String() {
			foundEtape2 = &vm.Etapes[i]
			break
		}
	}

	if foundEtape2 == nil {
		t.Fatal("etape2 not found in vm.Etapes")
	}

	if foundEtape2.TaskCount != 0 {
		t.Errorf("etape2: expected TaskCount=0, got %d", foundEtape2.TaskCount)
	}
}
