package protocol

import (
	"fmt"
	"io"
	"os"

	"github.com/steveyegge/gastown/internal/mail"
	"github.com/steveyegge/gastown/internal/witness"
)

// DefaultWitnessHandler provides the default implementation for Witness protocol handlers.
// It receives messages from the Refinery about merge outcomes and takes appropriate action.
type DefaultWitnessHandler struct {
	// Rig is the name of the rig this witness manages.
	Rig string

	// WorkDir is the working directory for operations.
	WorkDir string

	// Router is used to send mail messages.
	Router *mail.Router

	// Output is where to write status messages.
	Output io.Writer
}

// NewWitnessHandler creates a new DefaultWitnessHandler.
func NewWitnessHandler(rig, workDir string) *DefaultWitnessHandler {
	return &DefaultWitnessHandler{
		Rig:     rig,
		WorkDir: workDir,
		Router:  mail.NewRouter(workDir),
		Output:  os.Stdout,
	}
}

// SetOutput sets the output writer for status messages.
func (h *DefaultWitnessHandler) SetOutput(w io.Writer) {
	h.Output = w
}

// HandleMerged handles a MERGED message from Refinery.
// When a branch is successfully merged, the Witness:
// 1. Logs the success
// 2. Notifies the polecat of successful merge
// 3. Initiates polecat cleanup (nuke worktree)
func (h *DefaultWitnessHandler) HandleMerged(payload *MergedPayload) error {
	_, _ = fmt.Fprintf(h.Output, "[Witness] MERGED received for polecat %s\n", payload.Polecat)
	_, _ = fmt.Fprintf(h.Output, "  Branch: %s\n", payload.Branch)
	_, _ = fmt.Fprintf(h.Output, "  Issue: %s\n", payload.Issue)
	_, _ = fmt.Fprintf(h.Output, "  Merged to: %s\n", payload.TargetBranch)
	if payload.MergeCommit != "" {
		_, _ = fmt.Fprintf(h.Output, "  Commit: %s\n", payload.MergeCommit)
	}

	// Notify the polecat about successful merge
	if err := h.notifyPolecatMerged(payload); err != nil {
		fmt.Fprintf(h.Output, "[Witness] Warning: failed to notify polecat: %v\n", err)
		// Continue - notification is best-effort
	}

	// Initiate polecat cleanup using AutoNukeIfClean
	// This verifies cleanup_status before nuking to prevent work loss.
	nukeResult := witness.AutoNukeIfClean(h.WorkDir, h.Rig, payload.Polecat)
	if nukeResult.Nuked {
		fmt.Fprintf(h.Output, "[Witness] ✓ Auto-nuked polecat %s: %s\n", payload.Polecat, nukeResult.Reason)
	} else if nukeResult.Skipped {
		fmt.Fprintf(h.Output, "[Witness] ⚠ Cleanup skipped for %s: %s\n", payload.Polecat, nukeResult.Reason)
	} else if nukeResult.Error != nil {
		fmt.Fprintf(h.Output, "[Witness] ✗ Cleanup failed for %s: %v\n", payload.Polecat, nukeResult.Error)
	} else {
		fmt.Fprintf(h.Output, "[Witness] ✓ Polecat %s work merged, cleanup can proceed\n", payload.Polecat)
	}

	return nil
}

// HandleMergeFailed handles a MERGE_FAILED message from Refinery.
// When a merge fails (tests, build, etc.), the Witness:
// 1. Logs the failure
// 2. Notifies the polecat about the failure and required fixes
// 3. Updates the polecat's state to indicate rework needed
func (h *DefaultWitnessHandler) HandleMergeFailed(payload *MergeFailedPayload) error {
	fmt.Fprintf(h.Output, "[Witness] MERGE_FAILED received for polecat %s\n", payload.Polecat)
	fmt.Fprintf(h.Output, "  Branch: %s\n", payload.Branch)
	fmt.Fprintf(h.Output, "  Issue: %s\n", payload.Issue)
	fmt.Fprintf(h.Output, "  Failure type: %s\n", payload.FailureType)
	fmt.Fprintf(h.Output, "  Error: %s\n", payload.Error)

	// Notify the polecat about the failure
	if err := h.notifyPolecatFailed(payload); err != nil {
		fmt.Fprintf(h.Output, "[Witness] Warning: failed to notify polecat: %v\n", err)
		// Continue - notification is best-effort
	}

	fmt.Fprintf(h.Output, "[Witness] ✗ Polecat %s merge failed, rework needed\n", payload.Polecat)

	return nil
}

// HandleReworkRequest handles a REWORK_REQUEST message from Refinery.
// When a branch has conflicts requiring rebase, the Witness:
// 1. Logs the conflict
// 2. Notifies the polecat with rebase instructions
// 3. Updates the polecat's state to indicate rebase needed
func (h *DefaultWitnessHandler) HandleReworkRequest(payload *ReworkRequestPayload) error {
	fmt.Fprintf(h.Output, "[Witness] REWORK_REQUEST received for polecat %s\n", payload.Polecat)
	fmt.Fprintf(h.Output, "  Branch: %s\n", payload.Branch)
	fmt.Fprintf(h.Output, "  Issue: %s\n", payload.Issue)
	fmt.Fprintf(h.Output, "  Target: %s\n", payload.TargetBranch)
	if len(payload.ConflictFiles) > 0 {
		fmt.Fprintf(h.Output, "  Conflicts in: %v\n", payload.ConflictFiles)
	}

	// Notify the polecat about the rebase requirement
	if err := h.notifyPolecatRebase(payload); err != nil {
		fmt.Fprintf(h.Output, "[Witness] Warning: failed to notify polecat: %v\n", err)
		// Continue - notification is best-effort
	}

	fmt.Fprintf(h.Output, "[Witness] ⚠ Polecat %s needs to rebase onto %s\n", payload.Polecat, payload.TargetBranch)

	return nil
}

// notifyPolecatMerged sends a merge success notification to a polecat.
func (h *DefaultWitnessHandler) notifyPolecatMerged(payload *MergedPayload) error {
	msg := mail.NewMessage(
		fmt.Sprintf("%s/witness", h.Rig),
		fmt.Sprintf("%s/%s", h.Rig, payload.Polecat),
		"Work merged successfully",
		fmt.Sprintf(`Your work has been merged to %s.

Branch: %s
Issue: %s
Commit: %s

Thank you for your contribution! Your worktree will be cleaned up shortly.`,
			payload.TargetBranch,
			payload.Branch,
			payload.Issue,
			payload.MergeCommit,
		),
	)
	msg.Priority = mail.PriorityNormal

	return h.Router.Send(msg)
}

// notifyPolecatFailed sends a merge failure notification to a polecat.
func (h *DefaultWitnessHandler) notifyPolecatFailed(payload *MergeFailedPayload) error {
	msg := mail.NewMessage(
		fmt.Sprintf("%s/witness", h.Rig),
		fmt.Sprintf("%s/%s", h.Rig, payload.Polecat),
		fmt.Sprintf("Merge failed: %s", payload.FailureType),
		fmt.Sprintf(`Your merge request failed.

Branch: %s
Issue: %s
Failure: %s
Error: %s

Please fix the issue and resubmit your work with 'gt done'.`,
			payload.Branch,
			payload.Issue,
			payload.FailureType,
			payload.Error,
		),
	)
	msg.Priority = mail.PriorityHigh
	msg.Type = mail.TypeTask

	return h.Router.Send(msg)
}

// notifyPolecatRebase sends a rebase request notification to a polecat.
func (h *DefaultWitnessHandler) notifyPolecatRebase(payload *ReworkRequestPayload) error {
	conflictInfo := ""
	if len(payload.ConflictFiles) > 0 {
		conflictInfo = fmt.Sprintf("\nConflicting files:\n")
		for _, f := range payload.ConflictFiles {
			conflictInfo += fmt.Sprintf("  - %s\n", f)
		}
	}

	msg := mail.NewMessage(
		fmt.Sprintf("%s/witness", h.Rig),
		fmt.Sprintf("%s/%s", h.Rig, payload.Polecat),
		"Rebase required - merge conflict",
		fmt.Sprintf(`Your branch has conflicts with %s.

Branch: %s
Issue: %s
%s
Please rebase your changes:

  git fetch origin
  git rebase origin/%s
  # Resolve any conflicts
  git push -f

Then run 'gt done' to resubmit for merge.`,
			payload.TargetBranch,
			payload.Branch,
			payload.Issue,
			conflictInfo,
			payload.TargetBranch,
		),
	)
	msg.Priority = mail.PriorityHigh
	msg.Type = mail.TypeTask

	return h.Router.Send(msg)
}

// Ensure DefaultWitnessHandler implements WitnessHandler.
var _ WitnessHandler = (*DefaultWitnessHandler)(nil)
