package utils

import (
	"context"
	"fmt"
	"time"

	"github.com/chromedp/cdproto/page"
	"github.com/chromedp/chromedp"
)

// PdfOptions represents PDF generation options
type PdfOptions struct {
	PaperWidth      float64 `json:"paper_width"`      // Paper width in inches
	PaperHeight     float64 `json:"paper_height"`     // Paper height in inches
	MarginTop       float64 `json:"margin_top"`       // Top margin in inches
	MarginBottom    float64 `json:"margin_bottom"`    // Bottom margin in inches
	MarginLeft      float64 `json:"margin_left"`      // Left margin in inches
	MarginRight     float64 `json:"margin_right"`     // Right margin in inches
	Landscape       bool    `json:"landscape"`        // Landscape orientation
	PrintBackground bool    `json:"print_background"` // Print background graphics
	Timeout         int     `json:"timeout"`          // Timeout in seconds
	Scale           float64 `json:"scale"`            // Scale factor (0.1 to 2.0)
}

// DefaultPdfOptions returns default PDF generation options
func DefaultPdfOptions() PdfOptions {
	return PdfOptions{
		PaperWidth:      8.27,  // A4 width
		PaperHeight:     11.69, // A4 height
		MarginTop:       0.4,
		MarginBottom:    0.4,
		MarginLeft:      0.4,
		MarginRight:     0.4,
		Landscape:       false,
		PrintBackground: true,
		Timeout:         30,
		Scale:           1.0,
	}
}

// A4PortraitOptions returns A4 portrait options
func A4PortraitOptions() PdfOptions {
	return DefaultPdfOptions()
}

// A4LandscapeOptions returns A4 landscape options
func A4LandscapeOptions() PdfOptions {
	opts := DefaultPdfOptions()
	opts.Landscape = true
	opts.PaperWidth = 11.69
	opts.PaperHeight = 8.27
	return opts
}

// LetterPortraitOptions returns US Letter portrait options
func LetterPortraitOptions() PdfOptions {
	opts := DefaultPdfOptions()
	opts.PaperWidth = 8.5
	opts.PaperHeight = 11.0
	return opts
}

// LetterLandscapeOptions returns US Letter landscape options
func LetterLandscapeOptions() PdfOptions {
	opts := DefaultPdfOptions()
	opts.Landscape = true
	opts.PaperWidth = 11.0
	opts.PaperHeight = 8.5
	return opts
}

type PdfGenerator struct {
	pool chan struct{} // Semaphore for concurrency control
	ctx  context.Context
}

// NewPdfGenerator creates a new PDF generator with concurrency limit
func NewPdfGenerator() *PdfGenerator {
	// Limit to 3 concurrent PDF generations to save RAM
	return &PdfGenerator{
		pool: make(chan struct{}, 3),
		ctx:  context.Background(),
	}
}

// GenerateFromHtml converts HTML content to a PDF byte buffer
func (s *PdfGenerator) GenerateFromHtml(htmlContent string) ([]byte, error) {
	return s.GenerateFromHtmlWithOptions(htmlContent, DefaultPdfOptions())
}

// GenerateFromHtmlWithOptions converts HTML content to PDF with custom options
func (s *PdfGenerator) GenerateFromHtmlWithOptions(htmlContent string, opts PdfOptions) ([]byte, error) {
	return s.renderWithChromedp(opts,
		chromedp.Navigate("about:blank"),
		chromedp.ActionFunc(func(ctx context.Context) error {
			frameTree, err := page.GetFrameTree().Do(ctx)
			if err != nil {
				return err
			}
			return page.SetDocumentContent(frameTree.Frame.ID, htmlContent).Do(ctx)
		}),
		chromedp.WaitReady("body"),
		chromedp.Sleep(800*time.Millisecond), // Wait for fonts/styles
	)
}

// validateOptions validates PDF generation options
func (s *PdfGenerator) validateOptions(opts *PdfOptions) error {
	if opts.PaperWidth <= 0 || opts.PaperHeight <= 0 {
		return fmt.Errorf("paper dimensions must be positive")
	}
	if opts.MarginTop < 0 || opts.MarginBottom < 0 || opts.MarginLeft < 0 || opts.MarginRight < 0 {
		return fmt.Errorf("margins cannot be negative")
	}
	if opts.Timeout <= 0 {
		opts.Timeout = 30
	}
	if opts.Timeout > 300 {
		opts.Timeout = 300
	}
	if opts.Scale <= 0 {
		opts.Scale = 1.0
	}
	return nil
}

// GenerateFromUrl generates PDF from a URL
func (s *PdfGenerator) GenerateFromUrl(url string, opts PdfOptions) ([]byte, error) {
	return s.renderWithChromedp(opts,
		chromedp.Navigate(url),
		chromedp.WaitReady("body"),
		chromedp.Sleep(1500*time.Millisecond),
	)
}

// GetRomanMonth converts month number to Roman numeral
func GetRomanMonth(month int) string {
	romans := []string{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"}
	if month < 1 || month > 12 {
		return ""
	}
	return romans[month]
}

// GetIndonesianMonth converts month number to Indonesian month name
func GetIndonesianMonth(month int) string {
	months := []string{
		"", "Januari", "Februari", "Maret", "April", "Mei", "Juni",
		"Juli", "Agustus", "September", "Oktober", "November", "Desember",
	}
	if month < 1 || month > 12 {
		return ""
	}
	return months[month]
}

// GetIndonesianDay converts day number to Indonesian day name
func GetIndonesianDay(day int) string {
	days := []string{
		"Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu",
	}
	if day < 0 || day > 6 {
		return ""
	}
	return days[day]
}
