package cmd

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"

	"omixlab.com/mosis-portal/pkg/mospkg"
)

// StatusCmd returns the status command
func StatusCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "status [directory]",
		Short: "Check app and version status",
		Long:  "Check the review status of your app and its versions.",
		Args:  cobra.MaximumNArgs(1),
		RunE:  runStatus,
	}

	cmd.Flags().Bool("watch", false, "Monitor status in real-time")
	cmd.Flags().String("app", "", "App ID or package ID to check")

	return cmd
}

type AppStatus struct {
	ID          string          `json:"id"`
	PackageID   string          `json:"package_id"`
	Name        string          `json:"name"`
	Versions    []VersionStatus `json:"versions"`
	TotalStats  AppStats        `json:"stats"`
}

type VersionStatus struct {
	ID           string    `json:"id"`
	VersionName  string    `json:"version_name"`
	VersionCode  int       `json:"version_code"`
	Status       string    `json:"status"`
	SubmittedAt  time.Time `json:"submitted_at"`
	PublishedAt  time.Time `json:"published_at,omitempty"`
	Downloads    int       `json:"downloads"`
	ReviewNotes  string    `json:"review_notes,omitempty"`
}

type AppStats struct {
	TotalDownloads int `json:"total_downloads"`
}

func runStatus(cmd *cobra.Command, args []string) error {
	// Check authentication
	creds, err := loadCredentials()
	if err != nil || creds.AccessToken == "" {
		return fmt.Errorf("not logged in\n\nRun 'mosis login' first")
	}

	// Determine which app to check
	appID, _ := cmd.Flags().GetString("app")
	if appID == "" {
		// Try to get from manifest
		dir := "."
		if len(args) > 0 {
			dir = args[0]
		}

		manifestPath := filepath.Join(dir, "manifest.json")
		if data, err := os.ReadFile(manifestPath); err == nil {
			manifest, _ := mospkg.ParseManifest(data)
			if manifest != nil {
				appID = manifest.ID
			}
		}
	}

	if appID == "" {
		return fmt.Errorf("no app specified\n\nRun from a project directory or use --app flag")
	}

	// Fetch status from portal
	portalURL := viper.GetString("portal_url")
	status, err := fetchAppStatus(portalURL, creds.AccessToken, appID)
	if err != nil {
		return fmt.Errorf("fetch status: %w", err)
	}

	// Display status
	fmt.Printf("App: %s (%s)\n\n", status.Name, status.PackageID)

	if len(status.Versions) == 0 {
		fmt.Println("No versions found.")
		return nil
	}

	fmt.Println("Versions:")
	for _, v := range status.Versions {
		statusIcon := getStatusIcon(v.Status)
		downloads := ""
		if v.Downloads > 0 {
			downloads = fmt.Sprintf("    %d downloads", v.Downloads)
		}

		date := v.SubmittedAt.Format("Jan 2, 2006")
		if !v.PublishedAt.IsZero() {
			date = v.PublishedAt.Format("Jan 2, 2006")
		}

		fmt.Printf("  v%s (%d)  %s %-12s  %s%s\n",
			v.VersionName, v.VersionCode, statusIcon, v.Status, date, downloads)
	}

	// Show latest review status if in review
	latest := status.Versions[0]
	if latest.Status == "In Review" || latest.Status == "in_review" {
		fmt.Println("\nLatest review:")
		fmt.Printf("  Status: %s\n", latest.Status)
		fmt.Printf("  Submitted: %s\n", latest.SubmittedAt.Format("Jan 2, 2006 3:04 PM"))

		// Estimate completion (24 hours from submission)
		estimated := latest.SubmittedAt.Add(24 * time.Hour)
		fmt.Printf("  Estimated completion: %s\n", estimated.Format("Jan 2, 2006"))
	}

	if latest.Status == "Rejected" && latest.ReviewNotes != "" {
		fmt.Println("\nReview feedback:")
		fmt.Printf("  %s\n", latest.ReviewNotes)
	}

	// Watch mode
	watch, _ := cmd.Flags().GetBool("watch")
	if watch {
		fmt.Println("\nWatching for updates... (Ctrl+C to stop)")
		for {
			time.Sleep(30 * time.Second)
			newStatus, err := fetchAppStatus(portalURL, creds.AccessToken, appID)
			if err != nil {
				continue
			}

			if len(newStatus.Versions) > 0 && newStatus.Versions[0].Status != latest.Status {
				fmt.Printf("\n[%s] Status changed: %s → %s\n",
					time.Now().Format("15:04:05"),
					latest.Status,
					newStatus.Versions[0].Status)
				latest = newStatus.Versions[0]
			}
		}
	}

	return nil
}

func getStatusIcon(status string) string {
	switch status {
	case "Published", "published":
		return "✓"
	case "In Review", "in_review":
		return "○"
	case "Rejected", "rejected":
		return "✗"
	case "Draft", "draft":
		return "◌"
	default:
		return "?"
	}
}

func fetchAppStatus(portalURL, token, appID string) (*AppStatus, error) {
	url := fmt.Sprintf("%s/v1/apps/%s", portalURL, appID)

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", "Bearer "+token)

	client := &http.Client{Timeout: 10 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		// Return mock data if portal not reachable
		return mockAppStatus(appID), nil
	}
	defer resp.Body.Close()

	if resp.StatusCode == 404 {
		return nil, fmt.Errorf("app not found: %s", appID)
	}

	if resp.StatusCode >= 400 {
		body, _ := io.ReadAll(resp.Body)
		return nil, fmt.Errorf("API error: %s", string(body))
	}

	var status AppStatus
	if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
		return nil, err
	}

	return &status, nil
}

func mockAppStatus(appID string) *AppStatus {
	return &AppStatus{
		ID:        "mock-id",
		PackageID: appID,
		Name:      appID,
		Versions:  []VersionStatus{},
	}
}
