package cluster

import (
	"context"
	"fmt"
	"os"
	"strings"
)

// AWSCleanupFunc is called during destroy to clean up AWS resources.
// Returns a summary string, count of deleted resources, and any error.
type AWSCleanupFunc func(ctx context.Context, stateDir string) (summary string, deleted int, err error)

// LocalCleanupFunc performs Stage 1 best-effort local cleanup before cloud reaping.
type LocalCleanupFunc func(ctx context.Context) (summary string, err error)

// Destroyer handles cleanup of cp9 state and resources.
type Destroyer struct {
	StateDir     string
	ClusterName  string
	LocalCleanup LocalCleanupFunc
	AWSCleanup   AWSCleanupFunc
}

// DestroyResult holds the outcome of a destroy operation.
type DestroyResult struct {
	ClusterName       string `json:"cluster_name"`
	SessionDirRemoved bool   `json:"session_dir_removed"`
	LocalSummary      string `json:"local_summary,omitempty"`
	AWSCleaned        int    `json:"aws_cleaned"`
	AWSSummary        string `json:"aws_summary,omitempty"`
	Message           string `json:"message"`
}

// FormatText implements model.TextFormatter.
func (r *DestroyResult) FormatText() string {
	var parts []string
	if r.LocalSummary != "" {
		parts = append(parts, r.LocalSummary)
	}
	if r.SessionDirRemoved {
		parts = append(parts, "session dir removed")
	}
	if r.AWSSummary != "" {
		parts = append(parts, r.AWSSummary)
	}
	if r.Message != "" {
		parts = append(parts, r.Message)
	}
	return strings.Join(parts, ", ")
}

// Destroy cleans up local session resources only. Cloud cleanup is delegated to
// the GitHub cleanup workflow by the command layer before local state removal.
func (d *Destroyer) Destroy(ctx context.Context) (*DestroyResult, error) {
	result := &DestroyResult{ClusterName: d.ClusterName}

	if d.LocalCleanup != nil {
		summary, err := d.LocalCleanup(ctx)
		if err != nil {
			result.LocalSummary = fmt.Sprintf("local cleanup error: %v", err)
		} else {
			result.LocalSummary = summary
		}
	}

	// Remove the full session directory — validate cluster name matches if state exists.
	statePath := StatePath(d.StateDir)
	if _, err := os.Stat(statePath); err == nil {
		state, loadErr := LoadState(d.StateDir)
		if loadErr != nil {
			return result, fmt.Errorf("load state for validation: %w", loadErr)
		}
		if state.ClusterName != d.ClusterName {
			return result, fmt.Errorf("state file belongs to cluster %q, not %q — refusing to remove", state.ClusterName, d.ClusterName)
		}
		if err := os.RemoveAll(d.StateDir); err != nil {
			return result, fmt.Errorf("remove session dir: %w", err)
		}
		result.SessionDirRemoved = true
	} else if !os.IsNotExist(err) {
		return result, fmt.Errorf("stat state file: %w", err)
	} else if _, statErr := os.Stat(d.StateDir); statErr == nil {
		if err := os.RemoveAll(d.StateDir); err != nil {
			return result, fmt.Errorf("remove session dir: %w", err)
		}
		result.SessionDirRemoved = true
	} else if !os.IsNotExist(statErr) {
		return result, fmt.Errorf("stat session dir: %w", statErr)
	}

	if !result.SessionDirRemoved && result.AWSCleaned == 0 && result.LocalSummary == "" {
		result.Message = "nothing to clean up"
	}

	return result, nil
}
