package templates

import (
	"bytes"
	"fmt"
	"strings"

	. "primesys_email/src/models/report"

	"primesys_email/src/templates/utils"
	. "primesys_email/src/templates/utils"

	"github.com/xuri/excelize/v2"
)

const (
	colorTeal        = "015958"
	colorDarkTeal    = "014545"
	colorWhite       = "FFFFFF"
	colorText        = "222222"
	colorBorder      = "DDDDEE"
	colorAlternate   = "F4FAFA"
	colorName        = "015958"
	colorMeta        = "555555"
	colorTitle       = "1A1A1A"
	colorDoneBG      = "E1F5EE"
	colorDoneText    = "085041"
	colorOffBG       = "FCEBEB"
	colorOffText     = "791F1F"
	colorNotDoneBG   = "FAEEDA"
	colorNotDoneText = "633806"
	colorTotalBG     = "E6F5F4"
)

type KeymanReportExcel struct{}

func (k *KeymanReportExcel) CreateKeyManReportExcel(reports []DivisionTripReportModel, divisionName string, reportDate string) ([]byte, error) {
	f := excelize.NewFile()
	defer func() { _ = f.Close() }()

	const sheet = "Key Man Report"
	index, err := f.NewSheet(sheet)
	if err != nil {
		return nil, fmt.Errorf("create sheet: %w", err)
	}
	f.SetActiveSheet(index)
	_ = f.DeleteSheet("Sheet1")

	widths := []float64{32, 22, 22, 20, 22, 16, 16, 14, 14, 20, 20}
	for i, width := range widths {
		col, _ := excelize.ColumnNumberToName(i + 1)
		if err := f.SetColWidth(sheet, col, col, width); err != nil {
			return nil, err
		}
	}

	titleStyle := k.titleStyle(f)
	metaLabel := k.metaLabelStyle(f)
	metaValue := k.metaValueStyle(f)
	headerStyle := k.headerStyle(f, colorTeal)
	oddStyles := k.dataRowStyles(f, false)
	evenStyles := k.dataRowStyles(f, true)
	remarkStyles := k.remarkStyles(f)

	// Title row.
	_ = f.SetRowHeight(sheet, 1, 20)
	_ = f.SetCellValue(sheet, "A1", "Division Key Man Report")
	_ = f.MergeCell(sheet, "A1", "K1")
	_ = f.SetCellStyle(sheet, "A1", "K1", titleStyle)

	// Metadata row.
	_ = f.SetRowHeight(sheet, 2, 16)
	k.addMetaPair(f, sheet, "A2", "B2", "Division: ", divisionName+"    ", metaLabel, metaValue)
	k.addMetaPair(f, sheet, "C2", "D2", "Date: ", reportDate+"    ", metaLabel, metaValue)
	k.addMetaPair(f, sheet, "E2", "F2", "Total Devices: ", fmt.Sprint(len(reports)), metaLabel, metaValue)

	// Row 3 is the spacer.
	headers := []string{
		"Name", "Exp. Location", "Act. Location", "Exp. Time",
		"OnTrack Time", "Exp. KM", "Act. KM", "Exp. Trip",
		"Act. Trip", "Battery S–E", "Remarks",
	}

	headerRow := 4
	_ = f.SetRowHeight(sheet, headerRow, 18)
	for i, header := range headers {
		cell, _ := excelize.CoordinatesToCellName(i+1, headerRow)
		_ = f.SetCellValue(sheet, cell, header)
		_ = f.SetCellStyle(sheet, cell, cell, headerStyle)
	}

	for i, r := range reports {
		rowNum := headerRow + 1 + i
		_ = f.SetRowHeight(sheet, rowNum, 16)

		styles := oddStyles
		if i%2 != 0 {
			styles = evenStyles
		}

		remark := "-"
		if r.Remark != nil {
			remark = *r.Remark
		}

		values := []string{
			DefaultString(r.DeviceName),
			DefaultFloat(r.TripStartKm) + "–" + DefaultFloat(r.TripEndKm),
			DefaultFloat(r.TripActualStartKm) + "–" + DefaultFloat(r.TripActualEndKm),
			DefaultTime(r.TripStartTime) + "–" + DefaultTime(r.TripEndTime),
			DefaultTime(r.ActualStartTime) + "–" + DefaultTime(r.ActualEndTime),
			DefaultFloat(r.TripDistanceTobeCoverKm),
			DefaultFloat(r.DistanceCoverTrip),
			DefaultInt(r.AllocatedTrips),
			DefaultInt(r.ActualTrips),
			k.batteryRange(r.TripList),
			remark,
		}

		for col, value := range values {
			cell, _ := excelize.CoordinatesToCellName(col+1, rowNum)
			_ = f.SetCellValue(sheet, cell, value)

			style := styles[1]
			if col == 0 {
				style = styles[0]
			}
			if col == 10 {
				style = k.remarkStyle(remark, remarkStyles)
			}
			_ = f.SetCellStyle(sheet, cell, cell, style)
		}
	}

	return workbookBytes(f)
}

// ---------- Styles ----------

func (k *KeymanReportExcel) titleStyle(f *excelize.File) int {
	return createStyle(f, excelize.Style{
		Font: &excelize.Font{
			Family: "Arial", Size: 13, Bold: true, Color: colorTitle,
		},
		Alignment: &excelize.Alignment{Horizontal: "center"},
	})
}

func (k *KeymanReportExcel) metaLabelStyle(f *excelize.File) int {
	return createStyle(f, excelize.Style{
		Font: &excelize.Font{Family: "Arial", Size: 8, Color: colorMeta},
	})
}

func (k *KeymanReportExcel) metaValueStyle(f *excelize.File) int {
	return createStyle(f, excelize.Style{
		Font: &excelize.Font{Family: "Arial", Size: 8, Bold: true, Color: colorTitle},
	})
}

func (k *KeymanReportExcel) headerStyle(f *excelize.File, bg string) int {
	return createStyle(f, excelize.Style{
		Font: &excelize.Font{Family: "Arial", Size: 8, Bold: true, Color: colorWhite},
		Fill: excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{bg}},
		Alignment: &excelize.Alignment{
			Horizontal: "center", Vertical: "center", WrapText: true,
		},
		Border: ThinBorders(colorDarkTeal),
	})
}

func (k *KeymanReportExcel) dataRowStyles(f *excelize.File, even bool) []int {
	bg := colorWhite
	if even {
		bg = colorAlternate
	}

	name := createStyle(f, excelize.Style{
		Font:      &excelize.Font{Family: "Arial", Size: 8, Bold: true, Color: colorName},
		Fill:      excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{bg}},
		Alignment: &excelize.Alignment{Horizontal: "left", Vertical: "center"},
		Border:    ThinBorders(colorBorder),
	})

	normal := createStyle(f, excelize.Style{
		Font:      &excelize.Font{Family: "Arial", Size: 8, Color: colorText},
		Fill:      excelize.Fill{Type: "pattern", Pattern: 1, Color: []string{bg}},
		Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
		Border:    ThinBorders(colorBorder),
	})

	return []int{name, normal}
}

func (k *KeymanReportExcel) remarkStyles(f *excelize.File) []int {
	backgrounds := []string{colorDoneBG, colorOffBG, colorNotDoneBG}
	foregrounds := []string{colorDoneText, colorOffText, colorNotDoneText}

	styles := make([]int, 3)
	for i := range styles {
		styles[i] = createStyle(f, excelize.Style{
			Font: &excelize.Font{
				Family: "Arial", Size: 8, Bold: true, Color: foregrounds[i],
			},
			Fill: excelize.Fill{
				Type: "pattern", Pattern: 1, Color: []string{backgrounds[i]},
			},
			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
			Border:    ThinBorders(colorBorder),
		})
	}
	return styles
}

func createStyle(f *excelize.File, style excelize.Style) int {
	id, _ := f.NewStyle(&style)
	return id
}

// ---------- Cell helpers ----------

func (k *KeymanReportExcel) addMetaPair(
	f *excelize.File,
	sheet, labelCell, valueCell, label, value string,
	labelStyle, valueStyle int,
) {
	_ = f.SetCellValue(sheet, labelCell, label)
	_ = f.SetCellStyle(sheet, labelCell, labelCell, labelStyle)

	_ = f.SetCellValue(sheet, valueCell, value)
	_ = f.SetCellStyle(sheet, valueCell, valueCell, valueStyle)
}

func (k *KeymanReportExcel) remarkStyle(remark string, styles []int) int {
	switch {
	case strings.Contains(remark, "All work done"):
		return styles[0]
	case strings.Contains(remark, "Device was Off"):
		return styles[1]
	default:
		return styles[2]
	}
}

func (k *KeymanReportExcel) batteryRange(trips []TripReportStatusModel) string {
	var startBattery, endBattery int32

	if len(trips) > 0 {
		if trips[0].DeviceTripStartBatteryStatus != nil {
			startBattery = *trips[0].DeviceTripStartBatteryStatus
		}

		if trips[0].DeviceTripEndBatteryStatus != nil {
			endBattery = *trips[0].DeviceTripEndBatteryStatus
		}
	}

	return fmt.Sprintf("%s%% – %s%%", utils.BatteryPercent(startBattery), utils.BatteryPercent(endBattery))
}

func workbookBytes(f *excelize.File) ([]byte, error) {
	var out bytes.Buffer
	if err := f.Write(&out); err != nil {
		return nil, fmt.Errorf("write Excel workbook: %w", err)
	}
	return out.Bytes(), nil
}

// ---------- Value helpers ----------
