package pierre

import (
	"context"
	"fmt"
	"io"
	"strings"

	"git.schreifuchs.ch/schreifuchs/pierre-bot/internal/chatter"
)

// Service holds the core collaborators and configuration for Pierre.
// The order of the fields is intentional: configuration fields first (used
// during initialization) followed by the adapters. This prevents accidental
// changes to the serialized layout if encoding/gob or encoding/json is used
// elsewhere in the future.
type Service struct {
	maxChunkSize    int
	guidelines      []string // stored as slice of lines; legacy, see WithGuidelines
	disableComments bool
	git             GitAdapter
	chat            ChatAdapter
}

func New(chat ChatAdapter, git GitAdapter, maxChunkSize int, guidelines []string, disableComments bool) *Service {
	// Existing constructor retains slice based guidelines for backward compatibility.
	return &Service{
		git:             git,
		chat:            chat,
		maxChunkSize:    maxChunkSize,
		guidelines:      guidelines,
		disableComments: disableComments,
	}
}

// WithGuidelines parses a raw Markdown string (or any multiline string) into
// individual guideline lines, validates the line‑count (max 1000 non‑empty lines),
// and stores the result in the Service. It returns an error if validation fails.
// This is a convenience mutator for callers that have the guidelines as a
// single string.
func (s *Service) WithGuidelines(md string) error {
	lines, err := parseGuidelinesFromString(md)
	if err != nil {
		return err
	}
	s.guidelines = lines
	return nil
}

// parseGuidelinesFromString splits a markdown string into trimmed, non‑empty
// lines and ensures the total number of lines does not exceed 1000.
func parseGuidelinesFromString(md string) ([]string, error) {
	var result []string
	// Split on newline. Handles both \n and \r\n because TrimSpace removes \r.
	rawLines := strings.Split(md, "\n")
	for _, l := range rawLines {
		trimmed := strings.TrimSpace(l)
		if trimmed == "" {
			continue
		}
		result = append(result, trimmed)
	}
	if len(result) > 1000 {
		return nil, fmt.Errorf("guidelines exceed 1000 lines (found %d)", len(result))
	}
	return result, nil
}

type GitAdapter interface {
	GetDiff(ctx context.Context, owner, repo string, prID int) (io.ReadCloser, error)
	AddComment(ctx context.Context, owner, repo string, prID int, comment Comment) error
	GetFileContent(ctx context.Context, owner, repo, path, ref string) (string, error)
	GetPRHeadSHA(ctx context.Context, owner, repo string, prID int) (string, error)
}

type ChatAdapter interface {
	GenerateStructured(ctx context.Context, messages []chatter.Message, target interface{}) error
	GetProviderName() string
}
