package templates

import (
	"bytes"
	"fmt"

	. "primesys_email/src/models/report"
	. "primesys_email/src/templates/utils"

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

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

	const sheet = "Mate Report"

	defaultSheet := f.GetSheetName(0)
	if err := f.SetSheetName(defaultSheet, sheet); err != nil {
		return nil, err
	}

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

	titleStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   13,
			Bold:   true,
			Color:  "1A1A1A",
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
	})
	if err != nil {
		return nil, err
	}

	dateStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   13,
			Bold:   true,
			Color:  "5C70C4",
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
	})
	if err != nil {
		return nil, err
	}

	metaLabelStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Color:  "555555",
		},
	})
	if err != nil {
		return nil, err
	}

	metaValueStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "1A1A1A",
		},
	})
	if err != nil {
		return nil, err
	}

	headerStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "FFFFFF",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{"015958"},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
			WrapText:   true,
		},
		Border: reportBorders("014545"),
	})
	if err != nil {
		return nil, err
	}

	oddStyles, err := mateDataStyles(f, "FFFFFF")
	if err != nil {
		return nil, err
	}

	evenStyles, err := mateDataStyles(f, "F4FAFA")
	if err != nil {
		return nil, err
	}

	overspeedYesStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "791F1F",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{"FCEBEB"},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: reportBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

	overspeedNoStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "085041",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{"E1F5EE"},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: reportBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

	// Title row.
	if err := f.SetRowHeight(sheet, 1, 22); err != nil {
		return nil, err
	}
	_ = f.SetCellValue(sheet, "A1", "MATE REPORT")
	_ = f.SetCellStyle(sheet, "A1", "A1", titleStyle)
	_ = f.MergeCell(sheet, "A1", "J1")

	_ = f.SetCellValue(sheet, "K1", reportDate)
	_ = f.SetCellStyle(sheet, "K1", "K1", dateStyle)
	_ = f.MergeCell(sheet, "K1", "L1")

	// Metadata row.
	if err := f.SetRowHeight(sheet, 2, 16); err != nil {
		return nil, err
	}
	setMateMetaPair(f, sheet, "A2", "B2", "Division: ", divisionName+"    ", metaLabelStyle, metaValueStyle)
	setMateMetaPair(f, sheet, "C2", "D2", "Date: ", reportDate+"    ", metaLabelStyle, metaValueStyle)
	setMateMetaPair(f, sheet, "E2", "F2", "Total Devices: ", fmt.Sprint(len(reports)), metaLabelStyle, metaValueStyle)

	// Row 3 is the spacer.
	headers := []string{
		"Sr.No",
		"Name",
		"Expected Beat",
		"Actual Beat",
		"Expected Time",
		"OnTrack Time",
		"Expected KM",
		"Actual KM",
		"Expected Trip",
		"Actual Trip",
		"Overspeed",
		"Start% - End% Battery",
	}

	headerRow := 4
	if err := f.SetRowHeight(sheet, headerRow, 18); err != nil {
		return nil, err
	}

	for i, header := range headers {
		cell, err := excelize.CoordinatesToCellName(i+1, headerRow)
		if err != nil {
			return nil, err
		}
		_ = f.SetCellValue(sheet, cell, header)
		_ = f.SetCellStyle(sheet, cell, cell, headerStyle)
	}

	// Data rows start at row 5.
	for i, r := range reports {
		row := i + 5
		if err := f.SetRowHeight(sheet, row, 16); err != nil {
			return nil, err
		}

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

		values := []any{
			fmt.Sprint(i + 1),
			DefaultValue(*r.DeviceName),
			DefaultFloat(r.TripActualStartKm) + " - " + DefaultFloat(r.TripActualEndKm),
			DefaultFloat(r.TripActualStartKm) + " - " + DefaultFloat(r.TripActualEndKm),
			DefaultTime(r.TripStartTime) + " - " + DefaultTime(r.TripEndTime),
			DefaultTime(r.ActualStartTime) + " - " + DefaultTime(r.ActualEndTime),
			DefaultFloat(r.TripDistanceTobeCoverKm),
			FormatFloat64(r.DistanceCoverTrip),
			DefaultInt(r.AllocatedTrips),
			DefaultInt(r.ActualTrips),
			"-",
			mateBatteryText(r.TripList),
		}

		for col, value := range values {
			cell, err := excelize.CoordinatesToCellName(col+1, row)
			if err != nil {
				return nil, err
			}

			_ = f.SetCellValue(sheet, cell, value)

			styleID := styles[1]
			if col == 1 {
				styleID = styles[0]
			}
			_ = f.SetCellStyle(sheet, cell, cell, styleID)
		}

		// Overspeed column (K): missing data = "-", speed > 8 = Yes.
		speedAvailable := r.TripMaxSpeed != nil && r.TripList != nil && len(r.TripList) > 0

		overspeed := "-"
		overspeedStyle := styles[1]

		if speedAvailable {
			if *r.TripMaxSpeed > 8 {
				overspeed = "Yes"
				overspeedStyle = overspeedYesStyle
			} else {
				overspeed = "No"
				overspeedStyle = overspeedNoStyle
			}
		}

		_ = f.SetCellValue(sheet, fmt.Sprintf("K%d", row), overspeed)
		_ = f.SetCellStyle(sheet, fmt.Sprintf("K%d", row), fmt.Sprintf("K%d", row), overspeedStyle)

		// Battery column (L).
		_ = f.SetCellValue(sheet, fmt.Sprintf("L%d", row), mateBatteryText(r.TripList))
	}

	var buf bytes.Buffer
	if err := f.Write(&buf); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

func mateDataStyles(f *excelize.File, background string) ([]int, error) {
	nameStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "015958",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{background},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "left",
			Vertical:   "center",
		},
		Border: reportBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

	cellStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Color:  "222222",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{background},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: reportBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

	return []int{nameStyle, cellStyle}, nil
}

func reportBorders(color string) []excelize.Border {
	return []excelize.Border{
		{Type: "left", Color: color, Style: 1},
		{Type: "right", Color: color, Style: 1},
		{Type: "top", Color: color, Style: 1},
		{Type: "bottom", Color: color, Style: 1},
	}
}

func setMateMetaPair(
	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 FormatFloat64(value *float64) string {
	if value == nil {
		return "-"
	}
	return fmt.Sprintf("%.2f", *value)
}

func mateBatteryText(trips []TripReportStatusModel) string {
	return batteryText(trips, "- - -")
}
