package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
	"time"

	"chorus.services/bzzz/executor"
	"chorus.services/bzzz/logging"
	"chorus.services/bzzz/pkg/types"
	"chorus.services/bzzz/sandbox"
	"github.com/gorilla/mux"
)

// ChatTaskRequest represents a task request from the chat interface
type ChatTaskRequest struct {
	Method           string                 `json:"method"`
	Task             *types.EnhancedTask    `json:"task"`
	ExecutionOptions *ExecutionOptions      `json:"execution_options"`
	Callback         *CallbackConfig        `json:"callback"`
}

// ExecutionOptions defines how the task should be executed
type ExecutionOptions struct {
	SandboxImage      string `json:"sandbox_image"`
	Timeout           string `json:"timeout"`
	MaxIterations     int    `json:"max_iterations"`
	ReturnFullLog     bool   `json:"return_full_log"`
	CleanupOnComplete bool   `json:"cleanup_on_complete"`
}

// CallbackConfig defines where to send results
type CallbackConfig struct {
	WebhookURL       string `json:"webhook_url"`
	IncludeArtifacts bool   `json:"include_artifacts"`
}

// ChatTaskResponse represents the response from task execution
type ChatTaskResponse struct {
	TaskID         int                    `json:"task_id"`
	Status         string                 `json:"status"`
	ExecutionTime  string                 `json:"execution_time"`
	Artifacts      *ExecutionArtifacts    `json:"artifacts,omitempty"`
	ExecutionLog   []ExecutionLogEntry    `json:"execution_log,omitempty"`
	Errors         []ExecutionError       `json:"errors,omitempty"`
	GitBranch      string                 `json:"git_branch,omitempty"`
	PullRequestURL string                 `json:"pr_url,omitempty"`
	OriginalRequest *ChatTaskRequest      `json:"original_request,omitempty"`
}

// ExecutionArtifacts contains the outputs of task execution
type ExecutionArtifacts struct {
	FilesCreated    []FileArtifact `json:"files_created,omitempty"`
	CodeGenerated   string         `json:"code_generated,omitempty"`
	Language        string         `json:"language,omitempty"`
	TestsCreated    []FileArtifact `json:"tests_created,omitempty"`
	Documentation   string         `json:"documentation,omitempty"`
}

// FileArtifact represents a file created during execution
type FileArtifact struct {
	Name     string `json:"name"`
	Path     string `json:"path"`
	Size     int64  `json:"size"`
	Content  string `json:"content,omitempty"`
	Language string `json:"language,omitempty"`
}

// ExecutionLogEntry represents a single step in the execution process
type ExecutionLogEntry struct {
	Step      int       `json:"step"`
	Action    string    `json:"action"`
	Command   string    `json:"command,omitempty"`
	Result    string    `json:"result"`
	Success   bool      `json:"success"`
	Timestamp time.Time `json:"timestamp"`
	Duration  string    `json:"duration,omitempty"`
}

// ExecutionError represents an error that occurred during execution
type ExecutionError struct {
	Step    int    `json:"step,omitempty"`
	Type    string `json:"type"`
	Message string `json:"message"`
	Command string `json:"command,omitempty"`
}

// ChatAPIHandler handles chat integration requests
type ChatAPIHandler struct {
	logger *logging.HypercoreLog
}

// NewChatAPIHandler creates a new chat API handler
func NewChatAPIHandler() *ChatAPIHandler {
	// Note: HypercoreLog expects a peer.ID, but for testing we use nil
	// In production, this should be integrated with the actual P2P peer ID
	
	return &ChatAPIHandler{
		logger: nil, // Will be set up when P2P integration is available
	}
}

// ExecuteTaskHandler handles task execution requests from N8N chat workflow
func (h *ChatAPIHandler) ExecuteTaskHandler(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	
	// Parse request
	var req ChatTaskRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		h.sendError(w, http.StatusBadRequest, "Invalid request format", err)
		return
	}

	// Log the incoming request
	if h.logger != nil {
		h.logger.Append(logging.TaskProgress, map[string]interface{}{
			"task_id": req.Task.Number,
			"method":  req.Method,
			"source":  "chat_api",
			"status":  "received",
		})
	}

	// Validate request
	if req.Task == nil {
		h.sendError(w, http.StatusBadRequest, "Task is required", nil)
		return
	}

	// Send immediate response to N8N
	response := map[string]interface{}{
		"task_id": req.Task.Number,
		"status":  "accepted",
		"message": "Task accepted for execution",
	}
	
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(response)

	// Execute task asynchronously
	go h.executeTaskAsync(ctx, &req)
}

// executeTaskAsync executes the task in a separate goroutine
func (h *ChatAPIHandler) executeTaskAsync(ctx context.Context, req *ChatTaskRequest) {
	startTime := time.Now()
	var response ChatTaskResponse
	
	response.TaskID = req.Task.Number
	response.OriginalRequest = req

	// Create execution log
	var executionLog []ExecutionLogEntry
	var artifacts ExecutionArtifacts
	var errors []ExecutionError

	defer func() {
		response.ExecutionTime = time.Since(startTime).String()
		response.ExecutionLog = executionLog
		response.Artifacts = &artifacts
		response.Errors = errors
		
		// Send callback to N8N
		if req.Callback != nil && req.Callback.WebhookURL != "" {
			h.sendCallback(req.Callback.WebhookURL, &response)
		}
	}()

	// Log start of execution
	executionLog = append(executionLog, ExecutionLogEntry{
		Step:      1,
		Action:    "Starting task execution",
		Result:    fmt.Sprintf("Task: %s", req.Task.Title),
		Success:   true,
		Timestamp: time.Now(),
	})

	// Create sandbox
	sb, err := sandbox.CreateSandbox(ctx, req.ExecutionOptions.SandboxImage)
	if err != nil {
		response.Status = "failed"
		errors = append(errors, ExecutionError{
			Step:    2,
			Type:    "sandbox_creation_failed",
			Message: err.Error(),
		})
		return
	}

	// Ensure cleanup
	defer func() {
		if req.ExecutionOptions.CleanupOnComplete {
			sb.DestroySandbox()
		}
	}()

	executionLog = append(executionLog, ExecutionLogEntry{
		Step:      2,
		Action:    "Created sandbox",
		Result:    fmt.Sprintf("Sandbox ID: %s", sb.ID[:12]),
		Success:   true,
		Timestamp: time.Now(),
	})

	// Clone repository if specified
	if req.Task.GitURL != "" {
		cloneCmd := fmt.Sprintf("git clone %s .", req.Task.GitURL)
		result, err := sb.RunCommand(cloneCmd)
		
		success := err == nil
		executionLog = append(executionLog, ExecutionLogEntry{
			Step:      3,
			Action:    "Clone repository",
			Command:   cloneCmd,
			Result:    fmt.Sprintf("Exit: %d, Output: %s", result.ExitCode, result.StdOut),
			Success:   success,
			Timestamp: time.Now(),
		})

		if err != nil {
			errors = append(errors, ExecutionError{
				Step:    3,
				Type:    "git_clone_failed",
				Message: err.Error(),
				Command: cloneCmd,
			})
		}
	}

	// Execute the task using the existing executor
	result, err := executor.ExecuteTask(ctx, req.Task, h.logger)
	if err != nil {
		response.Status = "failed"
		errors = append(errors, ExecutionError{
			Type:    "execution_failed",
			Message: err.Error(),
		})
		return
	}

	// Collect artifacts from sandbox
	h.collectArtifacts(sb, &artifacts)

	// Set success status
	response.Status = "success"
	if result.BranchName != "" {
		response.GitBranch = result.BranchName
	}

	executionLog = append(executionLog, ExecutionLogEntry{
		Step:      len(executionLog) + 1,
		Action:    "Task completed successfully",
		Result:    fmt.Sprintf("Files created: %d", len(artifacts.FilesCreated)),
		Success:   true,
		Timestamp: time.Now(),
	})
}

// collectArtifacts gathers files and outputs from the sandbox
func (h *ChatAPIHandler) collectArtifacts(sb *sandbox.Sandbox, artifacts *ExecutionArtifacts) {
	// List files created in workspace
	result, err := sb.RunCommand("find . -type f -name '*.py' -o -name '*.js' -o -name '*.go' -o -name '*.java' -o -name '*.cpp' -o -name '*.rs' | head -20")
	if err == nil && result.StdOut != "" {
		files := strings.Split(strings.TrimSpace(result.StdOut), "\n")
		var validFiles []string
		for _, line := range files {
			if strings.TrimSpace(line) != "" {
				validFiles = append(validFiles, strings.TrimSpace(line))
			}
		}
		files = validFiles

		for _, file := range files {
			// Get file content
			content, err := sb.ReadFile(file)
			if err == nil && len(content) < 10000 { // Limit content size
				stat, _ := sb.RunCommand(fmt.Sprintf("stat -c '%%s' %s", file))
				size := int64(0)
				if stat.ExitCode == 0 {
					fmt.Sscanf(stat.StdOut, "%d", &size)
				}

				artifact := FileArtifact{
					Name:     file,
					Path:     file,
					Size:     size,
					Content:  string(content),
					Language: h.detectLanguage(file),
				}
				artifacts.FilesCreated = append(artifacts.FilesCreated, artifact)

				// If this looks like the main generated code, set it
				if artifacts.CodeGenerated == "" && size > 0 {
					artifacts.CodeGenerated = string(content)
					artifacts.Language = artifact.Language
				}
			}
		}
	}
}

// detectLanguage detects programming language from file extension
func (h *ChatAPIHandler) detectLanguage(filename string) string {
	extensions := map[string]string{
		".py":   "python",
		".js":   "javascript",
		".ts":   "typescript",
		".go":   "go",
		".java": "java",
		".cpp":  "cpp",
		".c":    "c",
		".rs":   "rust",
		".rb":   "ruby",
		".php":  "php",
	}

	for ext, lang := range extensions {
		if len(filename) > len(ext) && filename[len(filename)-len(ext):] == ext {
			return lang
		}
	}
	return "text"
}

// sendCallback sends the execution results back to N8N webhook
func (h *ChatAPIHandler) sendCallback(webhookURL string, response *ChatTaskResponse) {
	jsonData, err := json.Marshal(response)
	if err != nil {
		log.Printf("Failed to marshal callback response: %v", err)
		return
	}

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Post(webhookURL, "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Printf("Failed to send callback to %s: %v", webhookURL, err)
		return
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		log.Printf("Callback webhook returned status %d", resp.StatusCode)
	}
}

// sendError sends an error response
func (h *ChatAPIHandler) sendError(w http.ResponseWriter, statusCode int, message string, err error) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(statusCode)
	
	errorResponse := map[string]interface{}{
		"error":   message,
		"status":  statusCode,
	}
	
	if err != nil {
		errorResponse["details"] = err.Error()
	}
	
	json.NewEncoder(w).Encode(errorResponse)
}

// HealthHandler provides a health check endpoint
func (h *ChatAPIHandler) HealthHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"status":    "healthy",
		"service":   "bzzz-chat-api",
		"timestamp": time.Now().Format(time.RFC3339),
	})
}

// StartChatAPIServer starts the HTTP server for chat integration
func StartChatAPIServer(port string) {
	handler := NewChatAPIHandler()
	
	r := mux.NewRouter()
	
	// API routes
	api := r.PathPrefix("/bzzz/api").Subrouter()
	api.HandleFunc("/execute-task", handler.ExecuteTaskHandler).Methods("POST")
	api.HandleFunc("/health", handler.HealthHandler).Methods("GET")
	
	// Add CORS middleware
	r.Use(func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
			w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
			
			if r.Method == "OPTIONS" {
				w.WriteHeader(http.StatusOK)
				return
			}
			
			next.ServeHTTP(w, r)
		})
	})
	
	log.Printf("🚀 Starting Bzzz Chat API server on port %s", port)
	log.Printf("📡 Endpoints:")
	log.Printf("   POST /bzzz/api/execute-task - Execute task in sandbox")
	log.Printf("   GET  /bzzz/api/health - Health check")
	
	if err := http.ListenAndServe(":"+port, r); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

func main() {
	port := "8080"
	if len(os.Args) > 1 {
		port = os.Args[1]
	}
	
	StartChatAPIServer(port)
}