package recon

import (
	"fmt"
	"strings"

	github_recon_settings "github.com/anotherhadi/github-recon/settings"
	"github.com/anotherhadi/github-recon/utils"
	"github.com/google/go-github/v72/github"
)

type CommitsResult []CommitResult

type CommitResult struct {
	Name         string
	Email        string
	Occurrences  int
	FirstFoundIn string
}

func Commits(s github_recon_settings.Settings) (response CommitsResult) {
	results := make(map[string]CommitResult)

	collect := func(date string) error {
		for page := 1; page <= 10; page++ {
			result, resp, err := s.Client.Search.Commits(
				s.Ctx,
				fmt.Sprintf("author:%s author-date:%s", s.Target, date),
				&github.SearchOptions{
					Sort:        "author-date",
					Order:       "desc",
					ListOptions: github.ListOptions{PerPage: 100, Page: page},
				},
			)
			if err != nil {
				return fmt.Errorf("fetch page %d (%s): %w", page, date, err)
			}
			utils.WaitForRateLimit(s, resp)
			if len(result.Commits) == 0 {
				break
			}
			for _, item := range result.Commits {
				emails := []string{
					item.Commit.GetAuthor().GetEmail(),
					item.Commit.GetCommitter().GetEmail(),
					item.GetAuthor().GetEmail(),
					item.GetCommitter().GetEmail(),
				}

				names := []string{
					item.Commit.GetAuthor().GetName(),
					item.Commit.GetCommitter().GetName(),
					item.GetAuthor().GetName(),
					item.GetCommitter().GetName(),
				}

				for i := range names {
					name := names[i]
					email := emails[i]
					if utils.SkipResult(name, email) {
						continue
					}
					if name == "" || email == "" {
						continue
					}
					if _, seen := results[strings.ToLower(name)+" - "+strings.ToLower(email)]; !seen {
						author := CommitResult{
							Name:        name,
							Email:       email,
							Occurrences: 1,
							FirstFoundIn: item.GetRepository().Owner.GetLogin() + "/" + item.GetRepository().
								GetName(),
						}
						results[strings.ToLower(name)+" - "+strings.ToLower(email)] = author
					} else if i == 0 {
						result := results[strings.ToLower(name)+" - "+strings.ToLower(email)]
						result.Occurrences++
						results[strings.ToLower(name)+" - "+strings.ToLower(email)] = result
					}
				}
			}
		}
		return nil
	}

	// Range of dates to bypass the limit of 1000 results
	for _, date := range []string{
		"<2023-01-01", "2023-01-01..2023-12-31",
		"2024-01-01..2024-05-31",
		"2024-06-01..2024-12-31",
		"2025-01-01..2025-05-31",
		"2025-06-01..2025-12-31",
		">2026-01-01",
	} {
		if err := collect(date); err != nil {
			s.Logger.Error("Failed to fetch commits", "err", err, "date", date)
		}
	}

	for _, result := range results {
		response = append(response, result)
	}

	return
}
