package wikiv2

import (
	"context"
	"strings"
	"time"

	"github.com/pingcap/agent-git-service/internal/wikicatalog"
)

const (
	DefaultBranch = "master"
	PageExtension = ".md"
	DefaultRef    = "refs/heads/" + DefaultBranch
)

// PageMutation describes one planned git tree mutation for a wiki page.
type PageMutation struct {
	Slug    string
	Path    string
	Content []byte
	Delete  bool
}

// WritePlan is the minimal durable write contract for a future git-backed
// wiki mutation.
type WritePlan struct {
	Ref            string
	ExpectedOldSHA string
	Message        string
	Mutations      []PageMutation
}

// IndexPage is one derived live-page row for the Wiki V2 index.
type IndexPage struct {
	Slug          string
	Title         string
	HeadBlobSHA   string
	HeadCommitSHA string
	Size          int
	UpdatedAt     time.Time
	LastAuthorID  *uint
}

// IndexState is the derived reconciler progress state for one repository.
type IndexState struct {
	IndexedCommitSHA     string
	IndexedAt            *time.Time
	ReconcileRequestedAt *time.Time
	ReconcilerLeaseUntil *time.Time
}

// ReconcileRequest is the minimal repo-scoped reconcile contract.
type ReconcileRequest struct {
	RepositoryID       uint
	RepositoryFullName string
	WikiRepoFullName   string
	RequestedAt        time.Time
}

// ReconcileResult summarizes one manual reconcile run.
type ReconcileResult struct {
	RepositoryID     uint
	IndexedCommitSHA string
	PageCount        int
	Reconciled       bool
}

// Reconciler is the minimal service contract for a manual Wiki V2 index pass.
type Reconciler interface {
	Reconcile(context.Context, ReconcileRequest) (ReconcileResult, error)
}

// SlugToPath maps a wiki slug to its canonical git path.
func SlugToPath(slug string) (string, error) {
	if err := wikicatalog.ValidateWritable(slug); err != nil {
		return "", err
	}
	return slug + PageExtension, nil
}

// PathToSlug returns the wiki slug for a canonical git path.
func PathToSlug(path string) (string, bool) {
	path = strings.TrimSpace(path)
	if path == "" || strings.HasPrefix(path, ".") || !strings.HasSuffix(path, PageExtension) {
		return "", false
	}
	slug := strings.TrimSuffix(path, PageExtension)
	if err := wikicatalog.ValidateWritable(slug); err != nil {
		return "", false
	}
	return slug, true
}

// PlanPageUpsert creates the minimal write plan for one page create/update.
func PlanPageUpsert(slug string, content []byte, message, expectedOldSHA string) (WritePlan, error) {
	path, err := SlugToPath(slug)
	if err != nil {
		return WritePlan{}, err
	}
	return WritePlan{
		Ref:            DefaultRef,
		ExpectedOldSHA: strings.TrimSpace(expectedOldSHA),
		Message:        message,
		Mutations: []PageMutation{{
			Slug:    slug,
			Path:    path,
			Content: append([]byte(nil), content...),
		}},
	}, nil
}

// PlanPageDelete creates the minimal write plan for one page delete.
func PlanPageDelete(slug, message, expectedOldSHA string) (WritePlan, error) {
	path, err := SlugToPath(slug)
	if err != nil {
		return WritePlan{}, err
	}
	return WritePlan{
		Ref:            DefaultRef,
		ExpectedOldSHA: strings.TrimSpace(expectedOldSHA),
		Message:        message,
		Mutations: []PageMutation{{
			Slug:   slug,
			Path:   path,
			Delete: true,
		}},
	}, nil
}
