package uv

import (
	"testing"
)

func TestBorderConstructors(t *testing.T) {
	t.Run("NormalBorder", func(t *testing.T) {
		b := NormalBorder()
		if b.Top.Content != "─" || b.Bottom.Content != "─" || b.Left.Content != "│" || b.Right.Content != "│" {
			t.Fatalf("unexpected sides for NormalBorder")
		}
		if b.TopLeft.Content != "┌" || b.TopRight.Content != "┐" || b.BottomLeft.Content != "└" || b.BottomRight.Content != "┘" {
			t.Fatalf("unexpected corners for NormalBorder")
		}
	})

	t.Run("RoundedBorder", func(t *testing.T) {
		b := RoundedBorder()
		if b.Top.Content != "─" || b.Bottom.Content != "─" || b.Left.Content != "│" || b.Right.Content != "│" {
			t.Fatalf("unexpected sides for RoundedBorder")
		}
		if b.TopLeft.Content != "╭" || b.TopRight.Content != "╮" || b.BottomLeft.Content != "╰" || b.BottomRight.Content != "╯" {
			t.Fatalf("unexpected corners for RoundedBorder")
		}
	})

	t.Run("BlockBorder", func(t *testing.T) {
		b := BlockBorder()
		if b.Top.Content != "█" || b.Bottom.Content != "█" || b.Left.Content != "█" || b.Right.Content != "█" {
			t.Fatalf("unexpected sides for BlockBorder")
		}
		if b.TopLeft.Content != "█" || b.TopRight.Content != "█" || b.BottomLeft.Content != "█" || b.BottomRight.Content != "█" {
			t.Fatalf("unexpected corners for BlockBorder")
		}
	})

	t.Run("OuterHalfBlockBorder", func(t *testing.T) {
		b := OuterHalfBlockBorder()
		if b.Top.Content != "▀" || b.Bottom.Content != "▄" || b.Left.Content != "▌" || b.Right.Content != "▐" {
			t.Fatalf("unexpected sides for OuterHalfBlockBorder")
		}
		if b.TopLeft.Content != "▛" || b.TopRight.Content != "▜" || b.BottomLeft.Content != "▙" || b.BottomRight.Content != "▟" {
			t.Fatalf("unexpected corners for OuterHalfBlockBorder")
		}
	})

	t.Run("InnerHalfBlockBorder", func(t *testing.T) {
		b := InnerHalfBlockBorder()
		if b.Top.Content != "▄" || b.Bottom.Content != "▀" || b.Left.Content != "▐" || b.Right.Content != "▌" {
			t.Fatalf("unexpected sides for InnerHalfBlockBorder")
		}
		if b.TopLeft.Content != "▗" || b.TopRight.Content != "▖" || b.BottomLeft.Content != "▝" || b.BottomRight.Content != "▘" {
			t.Fatalf("unexpected corners for InnerHalfBlockBorder")
		}
	})

	t.Run("ThickBorder", func(t *testing.T) {
		b := ThickBorder()
		if b.Top.Content != "━" || b.Bottom.Content != "━" || b.Left.Content != "┃" || b.Right.Content != "┃" {
			t.Fatalf("unexpected sides for ThickBorder")
		}
		if b.TopLeft.Content != "┏" || b.TopRight.Content != "┓" || b.BottomLeft.Content != "┗" || b.BottomRight.Content != "┛" {
			t.Fatalf("unexpected corners for ThickBorder")
		}
	})

	t.Run("DoubleBorder", func(t *testing.T) {
		b := DoubleBorder()
		if b.Top.Content != "═" || b.Bottom.Content != "═" || b.Left.Content != "║" || b.Right.Content != "║" {
			t.Fatalf("unexpected sides for DoubleBorder")
		}
		if b.TopLeft.Content != "╔" || b.TopRight.Content != "╗" || b.BottomLeft.Content != "╚" || b.BottomRight.Content != "╝" {
			t.Fatalf("unexpected corners for DoubleBorder")
		}
	})

	t.Run("HiddenBorder", func(t *testing.T) {
		b := HiddenBorder()
		if b.Top.Content != " " || b.Bottom.Content != " " || b.Left.Content != " " || b.Right.Content != " " {
			t.Fatalf("unexpected sides for HiddenBorder")
		}
		if b.TopLeft.Content != " " || b.TopRight.Content != " " || b.BottomLeft.Content != " " || b.BottomRight.Content != " " {
			t.Fatalf("unexpected corners for HiddenBorder")
		}
	})

	t.Run("MarkdownBorder", func(t *testing.T) {
		b := MarkdownBorder()
		if b.Left.Content != "|" || b.Right.Content != "|" {
			t.Fatalf("unexpected sides for MarkdownBorder left/right")
		}
		if b.TopLeft.Content != "|" || b.TopRight.Content != "|" || b.BottomLeft.Content != "|" || b.BottomRight.Content != "|" {
			t.Fatalf("unexpected corners for MarkdownBorder")
		}
		if b.Top.Content != "" || b.Bottom.Content != "" {
			t.Fatalf("unexpected top/bottom content for MarkdownBorder")
		}
	})

	t.Run("ASCIIBorder", func(t *testing.T) {
		b := ASCIIBorder()
		if b.Top.Content != "-" || b.Bottom.Content != "-" || b.Left.Content != "|" || b.Right.Content != "|" {
			t.Fatalf("unexpected sides for ASCIIBorder")
		}
		if b.TopLeft.Content != "+" || b.TopRight.Content != "+" || b.BottomLeft.Content != "+" || b.BottomRight.Content != "+" {
			t.Fatalf("unexpected corners for ASCIIBorder")
		}
	})
}

func TestBorderStyleAndLink(t *testing.T) {
	base := NormalBorder()
	style := Style{Attrs: AttrBold}
	link := NewLink("https://example.com", "id=1")

	b := base.Style(style).Link(link)

	if !b.Top.Style.Equal(&style) || !b.Bottom.Style.Equal(&style) || !b.Left.Style.Equal(&style) || !b.Right.Style.Equal(&style) {
		t.Fatalf("style not applied to all sides")
	}
	if !b.TopLeft.Style.Equal(&style) || !b.TopRight.Style.Equal(&style) || !b.BottomLeft.Style.Equal(&style) || !b.BottomRight.Style.Equal(&style) {
		t.Fatalf("style not applied to all corners")
	}
	if !b.Top.Link.Equal(&link) || !b.Bottom.Link.Equal(&link) || !b.Left.Link.Equal(&link) || !b.Right.Link.Equal(&link) {
		t.Fatalf("link not applied to all sides")
	}
	if !b.TopLeft.Link.Equal(&link) || !b.TopRight.Link.Equal(&link) || !b.BottomLeft.Link.Equal(&link) || !b.BottomRight.Link.Equal(&link) {
		t.Fatalf("link not applied to all corners")
	}

	if !base.Top.Style.IsZero() || !base.Top.Link.IsZero() {
		t.Fatalf("base border modified by Style/Link")
	}
}

func TestBorderDrawNormal(t *testing.T) {
	dst := NewScreenBuffer(20, 10)
	area := Rect(1, 1, 6, 4)
	b := NormalBorder()
	b.Draw(&dst, area)

	if c := dst.CellAt(1, 1); c == nil || c.Content != "┌" {
		t.Fatalf("expected top-left corner")
	}
	if c := dst.CellAt(6, 1); c == nil || c.Content != "┐" {
		t.Fatalf("expected top-right corner")
	}
	if c := dst.CellAt(1, 4); c == nil || c.Content != "└" {
		t.Fatalf("expected bottom-left corner")
	}
	if c := dst.CellAt(6, 4); c == nil || c.Content != "┘" {
		t.Fatalf("expected bottom-right corner")
	}

	for x := 2; x <= 5; x++ {
		if c := dst.CellAt(x, 1); c == nil || c.Content != "─" {
			t.Fatalf("expected top edge at x=%d", x)
		}
		if c := dst.CellAt(x, 4); c == nil || c.Content != "─" {
			t.Fatalf("expected bottom edge at x=%d", x)
		}
	}
	for y := 2; y <= 3; y++ {
		if c := dst.CellAt(1, y); c == nil || c.Content != "│" {
			t.Fatalf("expected left edge at y=%d", y)
		}
		if c := dst.CellAt(6, y); c == nil || c.Content != "│" {
			t.Fatalf("expected right edge at y=%d", y)
		}
	}

	for y := 2; y <= 3; y++ {
		for x := 2; x <= 5; x++ {
			if c := dst.CellAt(x, y); c == nil || c.Content != " " {
				t.Fatalf("expected interior to be blank at %d,%d", x, y)
			}
		}
	}
}

func TestBorderDrawHiddenStyleLink(t *testing.T) {
	dst := NewScreenBuffer(10, 6)
	area := Rect(2, 2, 5, 3)
	style := Style{Attrs: AttrBold}
	link := NewLink("https://example.com")
	b := HiddenBorder().Style(style).Link(link)
	b.Draw(&dst, area)

	checkPos := []struct{ x, y int }{
		{2, 2}, {6, 2}, {2, 4}, {6, 4},
	}
	for x := 3; x <= 5; x++ {
		checkPos = append(checkPos, struct{ x, y int }{x, 2})
		checkPos = append(checkPos, struct{ x, y int }{x, 4})
	}
	for y := 3; y <= 3; y++ {
		checkPos = append(checkPos, struct{ x, y int }{2, y})
		checkPos = append(checkPos, struct{ x, y int }{6, y})
	}

	for _, p := range checkPos {
		c := dst.CellAt(p.x, p.y)
		if c == nil || c.Content != " " || !c.Style.Equal(&style) || !c.Link.Equal(&link) {
			t.Fatalf("expected styled/link space at %d,%d", p.x, p.y)
		}
	}

	c := dst.CellAt(4, 3)
	if c == nil || c.Content != " " || !c.Style.IsZero() || !c.Link.IsZero() {
		t.Fatalf("interior should be default space without style/link")
	}
}

func TestBorderDrawSmallAreas(t *testing.T) {
	dst := NewScreenBuffer(3, 3)
	b := NormalBorder()

	area1 := Rect(0, 0, 1, 1)
	b.Draw(&dst, area1)
	if c := dst.CellAt(0, 0); c == nil || c.Content != "┌" {
		t.Fatalf("expected single-cell area to use top-left corner")
	}

	area2 := Rect(0, 1, 1, 2)
	b.Draw(&dst, area2)
	if c := dst.CellAt(0, 1); c == nil || c.Content != "┌" {
		t.Fatalf("expected top-left at 0,1")
	}
	if c := dst.CellAt(0, 2); c == nil || c.Content != "└" {
		t.Fatalf("expected bottom-left at 0,2")
	}
}
