package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"time"

	"gopkg.in/yaml.v3"

	"github.com/olekukonko/tablewriter"
	"github.com/xanzy/go-gitlab"
)

type GitlabInternalIssueStruct struct {
	ID          int      `yaml:"ID"`
	Title       string   `yaml:"Title"`
	Description string   `yaml:"Description"`
	Priority    string   `yaml:"Priority"`
	Status      string   `yaml:"Status"`
	Assignee    string   `yaml:"Assignee"`
	Milestone   string   `yaml:"Milestone"`
	Labels      []string `yaml:"Labels"`
}

type Issue struct {
	GitlabIntern *GitlabInternalIssueStruct `yaml:"Gitlab"`
	GitlabRemote *gitlab.Issue
}

func loadIssuesFromGitlab(context *gitlabContext, issueID int) (*gitlab.Issue, error) {

	client := context.client

	issue, _, err := client.Issues.GetIssue(context.project.ID, issueID) //  .ListProjectIssues(context.project.ID, &gitlab.ListProjectIssuesOptions{})
	if err != nil {
		return nil, err
	}

	return issue, nil

	//err, pageData := collectStructureFromFiles(config.Path)
}

func buildIssueOverviewTable(config *Configuration, pageMap map[string]*requirement, extended bool) (error, string, bool) {

	buf := new(bytes.Buffer)
	has := false

	table := tablewriter.NewWriter(buf)

	header := []string{
		printer.Sprintf("ID"),
		printer.Sprintf("Title"),
		printer.Sprintf("State")}

	if extended == true {

		header = append(header, printer.Sprintf("Assignees"))
		header = append(header, printer.Sprintf("Due date"))
		header = append(header, printer.Sprintf("Labels"))
		header = append(header, printer.Sprintf("Estimate"))
		header = append(header, printer.Sprintf("Spent"))
	}

	table.SetHeader(header)

	table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
	table.SetCenterSeparator("|")

	var tableData [][]string

	for _, requirement := range pageMap {
		for _, issue := range requirement.Issues {

			gitlabIntern := issue.GitlabIntern

			if gitlabIntern == nil {
				continue
			}

			var col []string
			dueDate := "—"

			id := "—"
			labels := "—"
			estimate := "—"
			spent := "—"
			state := "—"
			title := "—"
			assignees := "—"

			id = printer.Sprintf("%d", gitlabIntern.ID)
			if gitlabIntern.Labels != nil {
				labels = strings.Join(gitlabIntern.Labels, ", ")
			}
			if gitlabIntern.Title != "" {
				title = gitlabIntern.Title
			}

			gitlabRemote := issue.GitlabRemote
			if gitlabRemote != nil {
				if gitlabRemote.DueDate != nil {
					d := (time.Time)(*gitlabRemote.DueDate)
					dueDate = d.Format(config.Locale.DateFormat)
				}

				labels = printer.Sprintf("%s", strings.Join(gitlabRemote.Labels, ", "))
				estimate = printer.Sprintf("%s", gitlabRemote.TimeStats.HumanTimeEstimate)
				spent = printer.Sprintf("%s", gitlabRemote.TimeStats.HumanTotalTimeSpent)
				state = printer.Sprintf(gitlabRemote.State)
				title = printer.Sprintf("%s", gitlabRemote.Title)

				a := []string{}
				for _, assignee := range gitlabRemote.Assignees {
					a = append(a, assignee.Name)
				}

				assignees = printer.Sprintf("%s", strings.Join(a, ", "))

			}

			if extended {
				col = []string{id, title, state, assignees, dueDate, labels, estimate, spent}
			} else {
				col = []string{id, title, state, labels}
			}

			tableData = append(tableData, col)
			has = true

		}

	}

	table.AppendBulk(tableData) // Add Bulk Data
	table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
	table.Render()

	return nil, buf.String(), has
}

func printIssueTable(config *Configuration, arguments *commandLineOptions) error {
	err, pageMap := collectStructureFromFiles(config.Path)

	if arguments.Issues.Print.Remote {
		enrichIssuesWithGitlab(pageMap, config)
		if err != nil {
			return err
		}
	}

	err, table, _ := buildIssueOverviewTable(config, pageMap, true)
	fmt.Println(table)

	return nil
}

func syncTasksWithGitlab(config *Configuration) error {

	err, pageData := collectStructureFromFiles(config.Path)
	if err != nil {
		return err
	}

	issuesList := []Issue{}

	for _, pageData := range pageData {
		for _, info := range pageData.Issues {
			issuesList = append(issuesList, info)
		}
	}

	context := getGitlabContext(config)
	searchProject(context)

	for filename, pd := range pageData {

		buf := new(bytes.Buffer)
		var encoder = yaml.NewEncoder(buf)
		err := encoder.Encode(pd.OriginNode)
		if err != nil {
			return err
		}
		encoder.Close()

		text := "---\n" + buf.String() + "\n...\n"
		text += pd.OriginText

		info, err := os.Stat(filename)
		if err != nil {
			return err
		}
		mode := info.Mode()

		err = os.WriteFile(filename, []byte(text), mode)
		if err != nil {
			return err
		}

	}

	return nil
}