package web

import (
	"math"
	"net/http"
	"strconv"

	"github.com/charmbracelet/log/v2"
	"github.com/charmbracelet/soft-serve/git"
	"github.com/charmbracelet/soft-serve/pkg/config"
	"github.com/charmbracelet/soft-serve/pkg/proto"
)

// BranchInfo contains branch reference and its latest commit.
type BranchInfo struct {
	Ref    *git.Reference
	Commit *git.Commit
}

// BranchesData contains data for rendering branches listing.
type BranchesData struct {
	RepoBaseData
	PaginationData
	Branches      []BranchInfo
	TotalBranches int
}

// repoBranches handles branches listing page.
func repoBranches(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	logger := log.FromContext(ctx)
	cfg := config.FromContext(ctx)
	repo := proto.RepositoryFromContext(ctx)

	gr, err := openRepository(repo)
	if err != nil {
		logger.Debug("failed to open repository", "repo", repo.Name(), "err", err)
		renderInternalServerError(w, r)
		return
	}

	defaultBranch := getDefaultBranch(gr)

	page := 1
	if pageStr := r.URL.Query().Get("page"); pageStr != "" {
		if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
			page = p
		}
	}

	// First fetch to get total count and calculate pages
	_, totalBranches, err := FetchRefsPaginated(gr, RefTypeBranch, 0, 1, defaultBranch)
	if err != nil {
		logger.Debug("failed to fetch branches", "repo", repo.Name(), "err", err)
		renderInternalServerError(w, r)
		return
	}

	totalPages := int(math.Ceil(float64(totalBranches) / float64(defaultBranchesPerPage)))
	if totalPages < 1 {
		totalPages = 1
	}

	// Clamp page before computing offset
	if page > totalPages {
		page = totalPages
	}
	if page < 1 {
		page = 1
	}

	// Calculate offset for pagination
	offset := (page - 1) * defaultBranchesPerPage

	// Fetch only the branches we need for this page, pre-sorted
	paginatedRefItems, _, err := FetchRefsPaginated(gr, RefTypeBranch, offset, defaultBranchesPerPage, defaultBranch)
	if err != nil {
		logger.Debug("failed to fetch branches", "repo", repo.Name(), "err", err)
		renderInternalServerError(w, r)
		return
	}

	var paginatedBranches []BranchInfo
	for _, refItem := range paginatedRefItems {
		paginatedBranches = append(paginatedBranches, BranchInfo{
			Ref:    refItem.Reference,
			Commit: refItem.Commit,
		})
	}

	data := BranchesData{
		RepoBaseData: RepoBaseData{
			BaseData: BaseData{
				ServerName: cfg.Name,
				ActiveTab:  "branches",
			},
			Repo:          repo,
			DefaultBranch: defaultBranch,
		},
		PaginationData: PaginationData{
			Page:        page,
			TotalPages:  totalPages,
			HasPrevPage: page > 1,
			HasNextPage: page < totalPages,
		},
		Branches:      paginatedBranches,
		TotalBranches: totalBranches,
	}

	renderHTML(w, "branches.html", data)
}
