package skills

import (
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type PatternMatch struct {
	Pattern     string
	Count       int
	LastSeen    time.Time
	ExampleText string
}

type AutoCreateProposal struct {
	Name         string
	Description  string
	SuggestedTags []string
	Category     string
	Patterns     []PatternMatch
	Confidence   float64
	CreatedFrom  string
}

type ConversationSnippet struct {
	Role      string    `json:"role"`
	Content   string    `json:"content"`
	Timestamp time.Time `json:"timestamp"`
}

func AnalyzeConversation(snippets []ConversationSnippet) []AutoCreateProposal {
	patterns := detectPatterns(snippets)
	var proposals []AutoCreateProposal

	for _, p := range patterns {
		if p.Count < 3 {
			continue
		}

		name := generateSkillName(p.Pattern)
		proposal := AutoCreateProposal{
			Name:          name,
			Description:   fmt.Sprintf("Auto-detected skill for recurring pattern: %s", p.Pattern),
			SuggestedTags: extractTags(p.Pattern),
			Category:      categorize(p.Pattern),
			Patterns:      []PatternMatch{p},
			Confidence:    computeConfidence(p),
			CreatedFrom:   "conversation",
		}
		proposals = append(proposals, proposal)
	}

	return proposals
}

func CreateFromProposal(proposal *AutoCreateProposal) (*Skill, error) {
	skill := &Skill{
		Name:        proposal.Name,
		Description: proposal.Description,
		Author:      "muyue-auto",
		Version:     "0.1.0",
		Tags:        proposal.SuggestedTags,
		Category:    proposal.Category,
		Target:      "both",
		CreatedFrom: proposal.CreatedFrom,
		AutoImprove: true,
		Content:     buildAutoSkillContent(proposal),
	}

	return skill, Create(skill)
}

func LoadProposals() ([]AutoCreateProposal, error) {
	dir, err := proposalsDir()
	if err != nil {
		return nil, err
	}

	entries, err := os.ReadDir(dir)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		return nil, err
	}

	var proposals []AutoCreateProposal
	for _, e := range entries {
		if e.IsDir() || !strings.HasSuffix(e.Name(), ".json") {
			continue
		}
		data, err := os.ReadFile(filepath.Join(dir, e.Name()))
		if err != nil {
			continue
		}
		var p AutoCreateProposal
		if err := json.Unmarshal(data, &p); err != nil {
			continue
		}
		proposals = append(proposals, p)
	}

	return proposals, nil
}

func SaveProposal(proposal *AutoCreateProposal) error {
	dir, err := proposalsDir()
	if err != nil {
		return err
	}
	if err := os.MkdirAll(dir, 0755); err != nil {
		return err
	}

	data, err := json.MarshalIndent(proposal, "", "  ")
	if err != nil {
		return err
	}

	path := filepath.Join(dir, proposal.Name+".json")
	return os.WriteFile(path, data, 0644)
}

func DeleteProposal(name string) error {
	dir, err := proposalsDir()
	if err != nil {
		return err
	}
	path := filepath.Join(dir, name+".json")
	return os.Remove(path)
}

func proposalsDir() (string, error) {
	dir, err := SkillsDir()
	if err != nil {
		return "", err
	}
	return filepath.Join(filepath.Dir(dir), ".muyue", "proposals"), nil
}

func detectPatterns(snippets []ConversationSnippet) []PatternMatch {
	commandPatterns := make(map[string]*PatternMatch)

	for _, s := range snippets {
		if s.Role != "assistant" {
			continue
		}
		lines := strings.Split(s.Content, "\n")
		for _, line := range lines {
			line = strings.TrimSpace(line)
			if isCommandPattern(line) {
				key := extractPatternKey(line)
				if key == "" {
					continue
				}
				if existing, ok := commandPatterns[key]; ok {
					existing.Count++
					if s.Timestamp.After(existing.LastSeen) {
						existing.LastSeen = s.Timestamp
						existing.ExampleText = truncate(line, 200)
					}
				} else {
					commandPatterns[key] = &PatternMatch{
						Pattern:     key,
						Count:       1,
						LastSeen:    s.Timestamp,
						ExampleText: truncate(line, 200),
					}
				}
			}
		}
	}

	var patterns []PatternMatch
	for _, p := range commandPatterns {
		patterns = append(patterns, *p)
	}
	return patterns
}

func isCommandPattern(line string) bool {
	toolPrefixes := []string{"go test", "go build", "go run", "npm test", "npm run",
		"docker build", "docker run", "git commit", "git push", "kubectl",
		"cargo test", "cargo build", "pytest", "make "}
	for _, prefix := range toolPrefixes {
		if strings.HasPrefix(line, prefix) {
			return true
		}
	}
	return false
}

func extractPatternKey(line string) string {
	parts := strings.Fields(line)
	if len(parts) < 2 {
		return ""
	}
	if len(parts) >= 3 && (parts[0] == "go" || parts[0] == "npm" || parts[0] == "cargo" || parts[0] == "git" || parts[0] == "docker") {
		return parts[0] + " " + parts[1]
	}
	return parts[0]
}

func generateSkillName(pattern string) string {
	name := strings.ReplaceAll(pattern, " ", "-")
	name = strings.ToLower(name)
	if len(name) > 30 {
		name = name[:30]
	}
	h := sha256.Sum256([]byte(pattern))
	return fmt.Sprintf("auto-%s-%x", name, h[:4])
}

func extractTags(pattern string) []string {
	var tags []string
	parts := strings.Fields(pattern)
	for _, p := range parts {
		if len(p) > 2 {
			tags = append(tags, strings.ToLower(p))
		}
	}
	return tags
}

func categorize(pattern string) string {
	categories := map[string]string{
		"go test": "testing", "go build": "build", "go run": "build",
		"npm test": "testing", "npm run": "build",
		"docker build": "devops", "docker run": "devops",
		"git commit": "workflow", "git push": "workflow",
		"kubectl": "devops", "cargo test": "testing",
		"cargo build": "build", "pytest": "testing",
		"make": "build",
	}
	for prefix, cat := range categories {
		if strings.HasPrefix(pattern, prefix) {
			return cat
		}
	}
	return "general"
}

func computeConfidence(p PatternMatch) float64 {
	confidence := 0.3
	confidence += float64(p.Count) * 0.1
	if confidence > 0.95 {
		confidence = 0.95
	}
	return confidence
}

func buildAutoSkillContent(proposal *AutoCreateProposal) string {
	var b strings.Builder
	b.WriteString(fmt.Sprintf("# %s\n\n", strings.Title(proposal.Name)))
	b.WriteString("Auto-generated skill based on recurring patterns detected in conversations.\n\n")
	b.WriteString("## Activation\n\n")
	b.WriteString("This skill activates when the following patterns are detected:\n\n")
	for _, p := range proposal.Patterns {
		b.WriteString(fmt.Sprintf("- `%s` (seen %d times)\n", p.Pattern, p.Count))
	}
	b.WriteString("\n## Instructions\n\n")
	b.WriteString("1. Detect the pattern context from the user request\n")
	b.WriteString("2. Apply the standard workflow for this pattern\n")
	b.WriteString("3. Handle common errors and edge cases\n")
	b.WriteString("4. Verify the result\n\n")
	b.WriteString("## Error Handling\n\n")
	b.WriteString("- If a command fails, check for missing dependencies\n")
	b.WriteString("- Suggest alternative approaches when the standard pattern doesn't fit\n")
	return b.String()
}

func truncate(s string, maxLen int) string {
	if len(s) <= maxLen {
		return s
	}
	return s[:maxLen]
}
