// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package interact

import (
	stdctx "context"
	"slices"
	"strings"

	"gitea.dev/tea/modules/config"
	"gitea.dev/tea/modules/context"
	"gitea.dev/tea/modules/task"
	"gitea.dev/tea/modules/theme"

	"charm.land/huh/v2"
)

// EditIssue interactively edits an issue
func EditIssue(requestCtx stdctx.Context, ctx context.TeaContext, index int64) (*task.EditIssueOption, error) {
	opts := task.EditIssueOption{}
	var err error

	ctx.Owner, ctx.Repo, err = promptRepoSlug(ctx.Owner, ctx.Repo)
	if err != nil {
		return &opts, err
	}
	printTitleAndContent("Target repo:", ctx.Owner+"/"+ctx.Repo)

	c := ctx.Login.Client()
	i, _, err := c.Issues.GetIssue(requestCtx, ctx.Owner, ctx.Repo, index)
	if err != nil {
		return &opts, err
	}

	opts = task.EditIssueOption{
		Index:    index,
		Title:    &i.Title,
		Body:     &i.Body,
		Deadline: i.Deadline,
	}

	if len(i.Assignees) != 0 {
		for _, a := range i.Assignees {
			opts.AddAssignees = append(opts.AddAssignees, a.UserName)
		}
	}

	if len(i.Labels) != 0 {
		for _, l := range i.Labels {
			opts.AddLabels = append(opts.AddLabels, l.Name)
		}
	}

	if i.Milestone != nil {
		opts.Milestone = &i.Milestone.Title
	}

	if err := promptIssueEditProperties(requestCtx, &ctx, &opts); err != nil {
		return &opts, err
	}

	return &opts, err
}

func promptIssueEditProperties(requestCtx stdctx.Context, ctx *context.TeaContext, o *task.EditIssueOption) error {
	var milestoneName string
	var labelsSelected []string
	var err error

	selectableChan := make(chan (issueSelectables), 1)
	go fetchIssueSelectables(requestCtx, ctx.Login, ctx.Owner, ctx.Repo, selectableChan)

	// title
	if err := huh.NewInput().
		Title("Issue title:").
		Value(o.Title).
		Validate(huh.ValidateNotEmpty()).
		WithTheme(theme.GetTheme()).
		Run(); err != nil {
		return err
	}
	printTitleAndContent("Issue title:", *o.Title)

	// description
	if err := huh.NewForm(
		huh.NewGroup(
			huh.NewText().
				Title("Issue description(markdown):").
				ExternalEditor(config.GetPreferences().Editor).
				EditorExtension("md").
				Value(o.Body),
		),
	).
		WithTheme(theme.GetTheme()).
		Run(); err != nil {
		return err
	}
	printTitleAndContent("Issue description(markdown):", *o.Body)

	// wait until selectables are fetched
	selectables := <-selectableChan
	if selectables.Err != nil {
		return selectables.Err
	}

	// skip remaining props if we don't have permission to set them
	if !selectables.Repo.Permissions.Push {
		return nil
	}

	currAssignees := o.AddAssignees
	newAssignees := selectables.Assignees

	for _, c := range currAssignees {
		if i := slices.Index(newAssignees, c); i != -1 {
			newAssignees = slices.Delete(newAssignees, i, i+1)
		}
	}

	// assignees
	if o.AddAssignees, err = promptMultiSelect("Add Assignees:", newAssignees, "[other]"); err != nil {
		return err
	}
	printTitleAndContent("Assignees:", strings.Join(o.AddAssignees, "\n"))

	// milestone
	if len(selectables.MilestoneList) != 0 {
		var defaultMS string
		if o.Milestone != nil {
			defaultMS = *o.Milestone
		}
		if milestoneName, err = promptSelect("Milestone:", selectables.MilestoneList, "", "[none]", defaultMS); err != nil {
			return err
		}
		o.Milestone = &milestoneName
		printTitleAndContent("Milestone:", milestoneName)
	}

	// labels
	if len(selectables.LabelList) != 0 {
		copy(labelsSelected, o.AddLabels)
		if err := huh.NewMultiSelect[string]().
			Title("Labels:").
			Options(huh.NewOptions(selectables.LabelList...)...).
			Value(&labelsSelected).
			WithTheme(theme.GetTheme()).
			Run(); err != nil {
			return err
		}
		printTitleAndContent("Labels:", strings.Join(labelsSelected, "\n"))

		// removed labels
		for _, l := range o.AddLabels {
			if !slices.Contains(labelsSelected, l) {
				o.RemoveLabels = append(o.RemoveLabels, l)
			}
		}
		// added labels
		o.AddLabels = make([]string, len(labelsSelected))
		for i, l := range labelsSelected {
			o.AddLabels[i] = l
		}
	}

	// deadline
	if o.Deadline, err = promptDatetime("Due date:"); err != nil {
		return err
	}
	deadlineStr := "No due date"
	if o.Deadline != nil && !o.Deadline.IsZero() {
		deadlineStr = o.Deadline.Format("2006-01-02")
	}
	printTitleAndContent("Due date:", deadlineStr)

	return nil
}
