package routes

import (
	"bssapp-backend/auth"
	"bssapp-backend/internal/i18n"
	"bssapp-backend/models"
	"bssapp-backend/queries"
	"bytes"
	"database/sql"
	"fmt"
	"log"
	"net/http"
	"runtime/debug"
	"sort"
	"strings"
	"time"

	"github.com/jung-kurt/gofpdf"
)

/* ============================ SABİTLER ============================ */

// A4 Landscape (mm)
const (
	hPageWidth  = 297.0
	hPageHeight = 210.0

	hMarginL = 8.0
	hMarginT = 8.0
	hMarginR = 8.0
	hMarginB = 15.0

	hLineHMain = 5.2
	hCellPadX  = 2.0

	hHeaderRowH = 8.4
	hGroupBarH  = 9.0

	hGridLineWidth = 0.3
	hLogoW         = 42.0
)

// Kolonlar
func hMainCols(lang string) []string {
	return []string{
		i18n.T(lang, "pdf.main.doc_no"),
		i18n.T(lang, "pdf.main.date"),
		i18n.T(lang, "pdf.main.due_date"),
		i18n.T(lang, "pdf.main.operation"),
		i18n.T(lang, "pdf.main.description"),
		i18n.T(lang, "pdf.main.currency"),
		i18n.T(lang, "pdf.main.debit"),
		i18n.T(lang, "pdf.main.credit"),
		i18n.T(lang, "pdf.main.balance"),
	}
}

var hMainWbase = []float64{
	34, 30, 28, 24, 60, 20, 36, 36, 36,
}

// Font dosyaları
const (
	hFontFamilyReg  = "dejavu"
	hFontFamilyBold = "dejavu"
)

// Renkler
var (
	hColorPrimary   = [3]int{149, 113, 22}  // #957116
	hColorSecondary = [3]int{218, 193, 151} // #dac197 (Baggi secondary)
)

/* ============================ FONT / FORMAT ============================ */

func hEnsureFonts(pdf *gofpdf.Fpdf) error {
	return registerDejavuFonts(pdf, hFontFamilyReg)
}

func hNormalizeWidths(base []float64, targetTotal float64) []float64 {
	sum := 0.0
	for _, v := range base {
		sum += v
	}
	scale := targetTotal / sum
	out := make([]float64, len(base))
	for i, v := range base {
		out[i] = v * scale
	}
	return out
}

func hFormatCurrencyTR(val float64) string {
	s := fmt.Sprintf("%.2f", val)
	parts := strings.Split(s, ".")
	intPart, decPart := parts[0], parts[1]

	var out []string
	for len(intPart) > 3 {
		out = append([]string{intPart[len(intPart)-3:]}, out...)
		intPart = intPart[:len(intPart)-3]
	}
	if intPart != "" {
		out = append([]string{intPart}, out...)
	}
	return strings.Join(out, ".") + "," + decPart
}

func hNeedNewPage(pdf *gofpdf.Fpdf, needH float64) bool {
	return pdf.GetY()+needH+hMarginB > hPageHeight
}

/* ============================ YARDIMCI FONKSİYONLAR ============================ */

func hSplitLinesSafe(pdf *gofpdf.Fpdf, text string, width float64) [][]byte {
	if width <= 0 {
		width = 1
	}
	return pdf.SplitLines([]byte(text), width)
}

func hDrawWrapText(pdf *gofpdf.Fpdf, text string, x, y, width, lineH float64) {
	if text == "" {
		return
	}
	lines := hSplitLinesSafe(pdf, text, width)
	cy := y
	for _, ln := range lines {
		pdf.SetXY(x, cy)
		pdf.CellFormat(width, lineH, string(ln), "", 0, "L", false, 0, "")
		cy += lineH
	}
}

func hCalcRowHeightForText(pdf *gofpdf.Fpdf, text string, colWidth, lineHeight, padX float64) float64 {
	if text == "" {
		return lineHeight
	}
	lines := hSplitLinesSafe(pdf, text, colWidth-(2*padX))
	h := float64(len(lines)) * lineHeight
	if h < lineHeight {
		h = lineHeight
	}
	return h
}

/* ============================ HEADER ============================ */

func hDrawPageHeader(pdf *gofpdf.Fpdf, lang, cariKod, cariIsim, start, end string) float64 {
	if logoPath, err := resolvePdfImagePath("Baggi-Tekstil-A.s-Logolu.jpeg"); err == nil {
		pdf.ImageOptions(logoPath, hMarginL, 2, hLogoW, 0, false, gofpdf.ImageOptions{}, 0, "")
	}

	// Başlıklar
	pdf.SetFont(hFontFamilyBold, "", 16)
	pdf.SetTextColor(hColorPrimary[0], hColorPrimary[1], hColorPrimary[2])
	pdf.SetXY(hMarginL+hLogoW+8, hMarginT+2)
	pdf.CellFormat(120, 7, "Baggi Software System", "", 0, "L", false, 0, "")

	pdf.SetFont(hFontFamilyBold, "", 12)
	pdf.SetXY(hMarginL+hLogoW+8, hMarginT+10)
	pdf.CellFormat(120, 6, i18n.T(lang, "pdf.report_title"), "", 0, "L", false, 0, "")

	// Bugünün tarihi (sağ üst)
	today := time.Now().Format("02.01.2006")
	pdf.SetFont(hFontFamilyReg, "", 9)
	pdf.SetXY(hPageWidth-hMarginR-40, hMarginT+3)
	pdf.CellFormat(40, 6, i18n.T(lang, "pdf.date")+": "+today, "", 0, "R", false, 0, "")

	// Cari & Tarih kutuları (daha yukarı taşındı)
	boxY := hMarginT + hLogoW - 6
	pdf.SetFont(hFontFamilyBold, "", 10)

	pdf.Rect(hMarginL, boxY, 140, 11, "")
	pdf.SetXY(hMarginL+2, boxY+3)
	pdf.CellFormat(136, 5, fmt.Sprintf("%s: %s — %s", i18n.T(lang, "pdf.customer"), cariKod, cariIsim), "", 0, "L", false, 0, "")

	pdf.Rect(hPageWidth-hMarginR-140, boxY, 140, 11, "")
	pdf.SetXY(hPageWidth-hMarginR-138, boxY+3)
	pdf.CellFormat(136, 5, fmt.Sprintf("%s: %s → %s", i18n.T(lang, "pdf.date_range"), start, end), "", 0, "R", false, 0, "")

	// Alt çizgi
	y := boxY + 13
	pdf.SetDrawColor(hColorPrimary[0], hColorPrimary[1], hColorPrimary[2])
	pdf.Line(hMarginL, y, hPageWidth-hMarginR, y)
	pdf.SetDrawColor(200, 200, 200)

	return y + 4
}

/* ============================ TABLO ============================ */

func hDrawGroupBar(pdf *gofpdf.Fpdf, lang, currency string, sonBakiye float64) {
	x := hMarginL
	y := pdf.GetY()
	w := hPageWidth - hMarginL - hMarginR
	h := hGroupBarH

	pdf.SetDrawColor(hColorPrimary[0], hColorPrimary[1], hColorPrimary[2])
	pdf.SetLineWidth(0.6)
	pdf.Rect(x, y, w, h, "")

	pdf.SetFont(hFontFamilyBold, "", 11.3)
	pdf.SetTextColor(hColorPrimary[0], hColorPrimary[1], hColorPrimary[2])

	pdf.SetXY(x+hCellPadX+1.0, y+(h-5.0)/2)
	pdf.CellFormat(w*0.6, 5.0, fmt.Sprintf("%s: %s", i18n.T(lang, "pdf.currency_prefix"), currency), "", 0, "L", false, 0, "")

	txt := i18n.T(lang, "pdf.ending_balance") + " = " + hFormatCurrencyTR(sonBakiye)
	pdf.SetXY(x+w*0.4, y+(h-5.0)/2)
	pdf.CellFormat(w*0.6-2.0, 5.0, txt, "", 0, "R", false, 0, "")

	pdf.SetLineWidth(hGridLineWidth)
	pdf.SetDrawColor(200, 200, 200)
	pdf.SetTextColor(0, 0, 0)

	pdf.Ln(h)
}

func hDrawMainHeaderRow(pdf *gofpdf.Fpdf, cols []string, widths []float64) {
	pdf.SetFont(hFontFamilyBold, "", 10.2)
	pdf.SetTextColor(255, 255, 255)
	pdf.SetFillColor(hColorPrimary[0], hColorPrimary[1], hColorPrimary[2])
	pdf.SetDrawColor(120, 90, 20)

	x := hMarginL
	y := pdf.GetY()
	for i, c := range cols {
		pdf.Rect(x, y, widths[i], hHeaderRowH, "DF")
		pdf.SetXY(x+hCellPadX, y+1.6)
		pdf.CellFormat(widths[i]-2*hCellPadX, hHeaderRowH-3.2, c, "", 0, "C", false, 0, "")
		x += widths[i]
	}
	pdf.Ln(hHeaderRowH)
}

func hDrawMainDataRow(pdf *gofpdf.Fpdf, row []string, widths []float64, rowH float64, rowIndex int) {
	x := hMarginL
	y := pdf.GetY()

	// ✅ Zebra efekti
	wTotal := hPageWidth - hMarginL - hMarginR
	if rowIndex%2 == 1 {
		pdf.SetFillColor(hColorSecondary[0], hColorSecondary[1], hColorSecondary[2])
		pdf.Rect(x, y, wTotal, rowH, "F")
	}

	pdf.SetFont(hFontFamilyReg, "", 8.2)
	pdf.SetDrawColor(242, 235, 222)
	pdf.SetTextColor(30, 30, 30)

	for i, val := range row {
		pdf.Rect(x, y, widths[i], rowH, "")
		switch {
		case i == 4: // Açıklama wrap
			hDrawWrapText(pdf, val, x+hCellPadX, y+0.5, widths[i]-2*hCellPadX, hLineHMain)
		case i >= 6:
			pdf.SetXY(x+hCellPadX, y+(rowH-hLineHMain)/2)
			pdf.CellFormat(widths[i]-2*hCellPadX, hLineHMain, val, "", 0, "R", false, 0, "")
		default:
			pdf.SetXY(x+hCellPadX, y+(rowH-hLineHMain)/2)
			pdf.CellFormat(widths[i]-2*hCellPadX, hLineHMain, val, "", 0, "L", false, 0, "")
		}
		x += widths[i]
	}

	// ❌ pdf.Ln(rowH) YOK
	// ✅ Manuel olarak Y'yi arttırıyoruz
	pdf.SetY(y + rowH)
}

/* ============================ MAIN HANDLER ============================ */

func ExportStatementHeaderReportPDFHandler(mssql *sql.DB) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if rec := recover(); rec != nil {
				log.Printf("❌ PANIC ExportStatementHeaderReportPDFHandler: %v", rec)
				debug.PrintStack()
				http.Error(w, fmt.Sprintf("header PDF panic: %v", rec), http.StatusInternalServerError)
			}
		}()

		claims, ok := auth.GetClaimsFromContext(r.Context())
		if !ok || claims == nil {
			http.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}

		started := time.Now()

		accountCode := r.URL.Query().Get("accountcode")
		startDate := r.URL.Query().Get("startdate")
		endDate := r.URL.Query().Get("enddate")
		langCode := i18n.ResolveLangCode(
			r.URL.Query().Get("langcode"),
			r.Header.Get("Accept-Language"),
		)
		rawParis := r.URL.Query()["parislemler"]

		var parislemler []string
		for _, v := range rawParis {
			v = strings.TrimSpace(v)
			if v != "" && v != "undefined" && v != "null" {
				parislemler = append(parislemler, v)
			}
		}

		headers, _, err := queries.GetStatementsHPDF(r.Context(), accountCode, startDate, endDate, langCode, parislemler)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		type grp struct {
			code      string
			rows      []models.StatementHeader
			sonBakiye float64
		}
		order := []string{}
		groups := map[string]*grp{}

		for _, h := range headers {
			g, ok := groups[h.ParaBirimi]
			if !ok {
				g = &grp{code: h.ParaBirimi}
				groups[h.ParaBirimi] = g
				order = append(order, h.ParaBirimi)
			}
			g.rows = append(g.rows, h)
		}
		for _, k := range order {
			sort.SliceStable(groups[k].rows, func(i, j int) bool {
				ri, rj := groups[k].rows[i], groups[k].rows[j]
				if ri.BelgeTarihi == rj.BelgeTarihi {
					return ri.BelgeNo < rj.BelgeNo
				}
				return ri.BelgeTarihi < rj.BelgeTarihi
			})
			if n := len(groups[k].rows); n > 0 {
				groups[k].sonBakiye = groups[k].rows[n-1].Bakiye
			}
		}

		pdf := gofpdf.New("L", "mm", "A4", "")
		pdf.SetMargins(hMarginL, hMarginT, hMarginR)
		pdf.SetAutoPageBreak(false, hMarginB)
		if err := hEnsureFonts(pdf); err != nil {
			http.Error(w, "PDF font yükleme hatası: "+err.Error(), http.StatusInternalServerError)
			return
		}

		wAvail := hPageWidth - hMarginL - hMarginR
		mainWn := hNormalizeWidths(hMainWbase, wAvail)

		cariIsim := ""
		if len(headers) > 0 {
			cariIsim = headers[0].CariIsim
		}

		pageNum := 0
		newPage := func() {
			pageNum++
			pdf.AddPage()
			tableTop := hDrawPageHeader(pdf, langCode, accountCode, cariIsim, startDate, endDate)
			pdf.SetY(tableTop)
		}

		newPage()

		for _, cur := range order {
			g := groups[cur]
			hDrawGroupBar(pdf, langCode, cur, g.sonBakiye)
			hDrawMainHeaderRow(pdf, hMainCols(langCode), mainWn)

			rowIndex := 0
			for _, h := range g.rows {
				row := []string{
					h.BelgeNo, h.BelgeTarihi, h.VadeTarihi, h.IslemTipi,
					h.Aciklama, h.ParaBirimi,
					hFormatCurrencyTR(h.Borc),
					hFormatCurrencyTR(h.Alacak),
					hFormatCurrencyTR(h.Bakiye),
				}

				rh := hCalcRowHeightForText(pdf, row[4], mainWn[4], hLineHMain, hCellPadX)
				if hNeedNewPage(pdf, rh+hHeaderRowH) {
					newPage()
					hDrawGroupBar(pdf, langCode, cur, g.sonBakiye)
					hDrawMainHeaderRow(pdf, hMainCols(langCode), mainWn)
				}

				hDrawMainDataRow(pdf, row, mainWn, rh, rowIndex)
				rowIndex++
			}
			pdf.Ln(1)
		}

		if err := pdf.Error(); err != nil {
			http.Error(w, "PDF render hatası: "+err.Error(), http.StatusInternalServerError)
			return
		}

		var buf bytes.Buffer
		if err := pdf.Output(&buf); err != nil {
			http.Error(w, "PDF oluşturulamadı: "+err.Error(), http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/pdf")
		w.Header().Set("Content-Disposition", "inline; filename=statement-header-report.pdf")
		_, _ = w.Write(buf.Bytes())

		log.Printf("✅ Header-only PDF üretimi tamamlandı (%s)", time.Since(started))
	}
}
