package client

import (
	"context"
	"io"
	"time"

	"github.com/andygrunwald/go-jira"
)

type SearchResults struct {
	IsLast        bool         `json:"isLast" structs:"isLast"`
	Issues        []jira.Issue `json:"issues" structs:"issues"`
	NextPageToken string       `json:"nextPageToken" structs:"nextPageToken"`
}

type SearchOptions struct {
	// NextPageToken is the token for a page to fetch that is not the first page.
	NextPageToken string
	// TMaxResults is tje maximum number of items to return per page.
	MaxResults int
	// Fields is a list of fields to return for each issue, use it to retrieve a subset of fields
	//
	// * `*all` Returns all fields.
	// * `*navigable` Returns navigable fields.
	// * `id` Returns only issue IDs.
	// * Any issue field, prefixed with a minus to exclude.
	//
	// The default is `id`.
	Fields []string
	// Use expand to include additional information about issues in the response.
	Expand string
	// FailFast means fail this request early if we can't retrieve all field data.
	FailFast bool
}

type ListIssueCommentsOptions struct {
	StartAt    int
	MaxResults int
	OrderBy    string
}

type ListIssueCommentsResult struct {
	StartAt    int             `json:"startAt"`
	MaxResults int             `json:"maxResults"`
	Total      int             `json:"total"`
	Comments   []*jira.Comment `json:"comments"`
	IsLast     bool            `json:"-"`
}

type ListIssueChangelogsOptions struct {
	StartAt    int
	MaxResults int
}

type IssueChangelogItem struct {
	Field      string `json:"field"`
	FieldID    string `json:"fieldId"`
	From       any    `json:"from"`
	FromString string `json:"fromString"`
	To         any    `json:"to"`
	ToString   string `json:"toString"`
}

type IssueChangelogHistory struct {
	ID      string               `json:"id"`
	Author  jira.User            `json:"author"`
	Created string               `json:"created"`
	Items   []IssueChangelogItem `json:"items"`
}

type ListIssueChangelogsResult struct {
	StartAt    int                     `json:"startAt"`
	MaxResults int                     `json:"maxResults"`
	Total      int                     `json:"total"`
	Values     []IssueChangelogHistory `json:"values"`
	IsLast     bool                    `json:"-"`
}

type ProjectComponent struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

const (
	EventTypeIssueCreated    = "issue_created"
	EventTypeIssueUpdated    = "issue_updated"
	EventTypeStatusChanged   = "status_changed"
	EventTypeAssigneeChanged = "assignee_changed"
)

type JiraWebhookEvent struct {
	EventID    string                       `json:"eventID"`
	EventType  string                       `json:"eventType"`
	OccurredAt time.Time                    `json:"occurredAt"`
	Issue      JiraWebhookEventIssuePayload `json:"issue"`
}

type JiraWebhookEventIssuePayload struct {
	ID              string     `json:"id"`
	Key             string     `json:"key"`
	Summary         string     `json:"summary"`
	Status          string     `json:"status"`
	Assignee        string     `json:"assignee"`
	StatusChangedAt *time.Time `json:"statusChangedAt,omitempty"`
}

type JiraClient interface {
	Raw() *jira.Client
	CustomFieldSet() CustomFieldSet

	ListVersions(ctx context.Context, project string) ([]jira.Version, error)
	ListProjectComponents(ctx context.Context, projectKey string) ([]ProjectComponent, error)

	SearchIssues(ctx context.Context, jql string, options *SearchOptions) (*SearchResults, error)
	GetIssue(ctx context.Context, name string, options *jira.GetQueryOptions) (*jira.Issue, error)
	ListIssueComments(ctx context.Context, issueKey string, options *ListIssueCommentsOptions) (*ListIssueCommentsResult, error)
	ListIssueChangelogs(ctx context.Context, issueKey string, options *ListIssueChangelogsOptions) (*ListIssueChangelogsResult, error)
	ResolveAccountIDByEmail(ctx context.Context, email string) (string, error)
	UpdateAssignee(ctx context.Context, name string, assignee string) error
	UpdateL2Assignee(ctx context.Context, name string, assignee string) error
	UpdateIssueStatus(ctx context.Context, name string, status string) error
	CreateIssue(ctx context.Context, issue *jira.Issue) (*jira.Issue, error)
	AddIssueLabel(ctx context.Context, issueKey, label string) error
	RemoveIssueLabel(ctx context.Context, issueKey, label string) error
	AddInternalComment(ctx context.Context, issueKey, body string) error
	CreateIssueLink(ctx context.Context, linkTypeID, outwardIssueKey, inwardIssueKey string) error
	DownloadAttachment(ctx context.Context, attachmentID string) (io.ReadCloser, error)
	UploadAttachment(ctx context.Context, issueKey, filename string, content io.Reader) error
}
