package main

import (
	"encoding/json"
	"fmt"
	"os"
	"text/tabwriter"
	"time"

	"warpbox/lib/boxstore"
	"warpbox/lib/models"
)

// ── List output ──────────────────────────────────────────────

func formatBoxSummariesTable(summaries []models.BoxSummary) error {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "ID\tFiles\tSize\tCreated\tExpires\tPassword\tOne-Time\tExpired")
	for _, s := range summaries {
		expires := "-"
		if !s.ExpiresAt.IsZero() {
			expires = s.ExpiresAt.Format("2006-01-02 15:04:05")
		}
		created := s.CreatedAt.Format("2006-01-02 15:04:05")
		fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%v\t%v\t%v\n",
			s.ID, s.FileCount, s.TotalSizeLabel, created, expires,
			s.PasswordProtected, s.OneTimeDownload, s.Expired)
	}
	return w.Flush()
}

func formatBoxSummariesJSON(summaries []models.BoxSummary) error {
	type summaryOut struct {
		ID                string    `json:"id"`
		FileCount         int       `json:"file_count"`
		TotalSize         int64     `json:"total_size"`
		TotalSizeLabel    string    `json:"total_size_label"`
		CreatedAt         time.Time `json:"created_at"`
		ExpiresAt         time.Time `json:"expires_at"`
		Expired           bool      `json:"expired"`
		OneTimeDownload   bool      `json:"one_time_download"`
		PasswordProtected bool      `json:"password_protected"`
	}
	out := make([]summaryOut, len(summaries))
	for i, s := range summaries {
		out[i] = summaryOut{
			ID: s.ID, FileCount: s.FileCount, TotalSize: s.TotalSize,
			TotalSizeLabel: s.TotalSizeLabel, CreatedAt: s.CreatedAt,
			ExpiresAt: s.ExpiresAt, Expired: s.Expired,
			OneTimeDownload: s.OneTimeDownload, PasswordProtected: s.PasswordProtected,
		}
	}
	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	return enc.Encode(out)
}

// ── View output ──────────────────────────────────────────────

func formatBoxSummaryJSON(s *models.BoxSummary) error {
	type summaryOut struct {
		ID                string    `json:"id"`
		FileCount         int       `json:"file_count"`
		TotalSize         int64     `json:"total_size"`
		TotalSizeLabel    string    `json:"total_size_label"`
		CreatedAt         time.Time `json:"created_at"`
		ExpiresAt         time.Time `json:"expires_at"`
		Expired           bool      `json:"expired"`
		OneTimeDownload   bool      `json:"one_time_download"`
		PasswordProtected bool      `json:"password_protected"`
	}
	out := summaryOut{
		ID: s.ID, FileCount: s.FileCount, TotalSize: s.TotalSize,
		TotalSizeLabel: s.TotalSizeLabel, CreatedAt: s.CreatedAt,
		ExpiresAt: s.ExpiresAt, Expired: s.Expired,
		OneTimeDownload: s.OneTimeDownload, PasswordProtected: s.PasswordProtected,
	}
	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	return enc.Encode(out)
}

func printBoxSummary(s *models.BoxSummary) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintf(w, "ID:\t%s\n", s.ID)
	fmt.Fprintf(w, "Files:\t%d\n", s.FileCount)
	fmt.Fprintf(w, "Total Size:\t%s\n", s.TotalSizeLabel)
	if !s.CreatedAt.IsZero() {
		fmt.Fprintf(w, "Created:\t%s\n", s.CreatedAt.Format(time.RFC3339))
	}
	if !s.ExpiresAt.IsZero() {
		fmt.Fprintf(w, "Expires:\t%s\n", s.ExpiresAt.Format(time.RFC3339))
	}
	fmt.Fprintf(w, "Expired:\t%v\n", s.Expired)
	fmt.Fprintf(w, "Password Protected:\t%v\n", s.PasswordProtected)
	fmt.Fprintf(w, "One-Time Download:\t%v\n", s.OneTimeDownload)
	w.Flush()
}

// ── Get output ───────────────────────────────────────────────

func formatBoxGetJSON(boxID string, manifest models.BoxManifest) error {
	type getOut struct {
		BoxID             string    `json:"box_id"`
		URL               string    `json:"url"`
		CreatedAt         time.Time `json:"created_at,omitempty"`
		ExpiresAt         time.Time `json:"expires_at,omitempty"`
		Expired           bool      `json:"expired"`
		PasswordProtected bool      `json:"password_protected"`
		OneTimeDownload   bool      `json:"one_time_download"`
		RetentionKey      string    `json:"retention_key,omitempty"`
		RetentionLabel    string    `json:"retention_label,omitempty"`
	}
	out := getOut{
		BoxID: boxID, URL: "/box/" + boxID,
		Expired: boxstore.IsExpired(manifest),
	}
	if !manifest.CreatedAt.IsZero() {
		out.CreatedAt = manifest.CreatedAt
	}
	if !manifest.ExpiresAt.IsZero() {
		out.ExpiresAt = manifest.ExpiresAt
	}
	out.PasswordProtected = boxstore.IsPasswordProtected(manifest)
	out.OneTimeDownload = manifest.OneTimeDownload
	out.RetentionKey = manifest.RetentionKey
	out.RetentionLabel = manifest.RetentionLabel
	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	return enc.Encode(out)
}

// ── Change output ────────────────────────────────────────────

func formatChangeResultJSON(boxID string, manifest models.BoxManifest) error {
	type changeOut struct {
		BoxID             string    `json:"box_id"`
		Updated           bool      `json:"updated"`
		CreatedAt         time.Time `json:"created_at,omitempty"`
		ExpiresAt         time.Time `json:"expires_at,omitempty"`
		Expired           bool      `json:"expired"`
		PasswordProtected bool      `json:"password_protected"`
		OneTimeDownload   bool      `json:"one_time_download"`
		DisableZip        bool      `json:"disable_zip"`
		RetentionKey      string    `json:"retention_key,omitempty"`
		RetentionLabel    string    `json:"retention_label,omitempty"`
		RetentionSeconds  int64     `json:"retention_seconds,omitempty"`
		FileCount         int       `json:"file_count"`
	}
	out := changeOut{
		BoxID: boxID, Updated: true,
		Expired:           boxstore.IsExpired(manifest),
		PasswordProtected: boxstore.IsPasswordProtected(manifest),
		OneTimeDownload:   manifest.OneTimeDownload,
		DisableZip:        manifest.DisableZip,
		RetentionKey:      manifest.RetentionKey,
		RetentionLabel:    manifest.RetentionLabel,
		RetentionSeconds:  manifest.RetentionSecs,
		FileCount:         len(manifest.Files),
	}
	if !manifest.CreatedAt.IsZero() {
		out.CreatedAt = manifest.CreatedAt
	}
	if !manifest.ExpiresAt.IsZero() {
		out.ExpiresAt = manifest.ExpiresAt
	}
	enc := json.NewEncoder(os.Stdout)
	enc.SetIndent("", "  ")
	return enc.Encode(out)
}

// ── Retention options ────────────────────────────────────────

func printRetentionOptions() {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
	fmt.Fprintln(w, "Key\tLabel\tSeconds")
	for _, opt := range boxstore.RetentionOptions() {
		fmt.Fprintf(w, "%s\t%s\t%d\n", opt.Key, opt.Label, opt.Seconds)
	}
	w.Flush()
}
