package templates

import (
	"bytes"
	"fmt"
	"strings"

	. "primesys_email/src/models/report"

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

type SectionCountReportExcel struct{}

func (s *SectionCountReportExcel) CreateSectionCountReportExcel(sections []SectionCountReport, divisionName string, reportDate string) ([]byte, error) {
	f := excelize.NewFile()
	defer func() {
		_ = f.Close()
	}()

	const sheet = "Section Count Report"

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

	// Sr.No, Section Name, Total Device, Beat Completed,
	// Beat Not Completed, Device Off, OverSpeed
	widths := []float64{14, 36, 22, 26, 30, 22, 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 := s.titleStyle(f, "1A1A1A")
	if err != nil {
		return nil, err
	}

	dateStyle, err := s.titleStyle(f, "5C70C4")
	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
	}

	totalStyle := TotalRowStyle(f)

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

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

	// Title row.
	if err := f.SetRowHeight(sheet, 1, 22); err != nil {
		return nil, err
	}
	s.setValue(f, sheet, "A1", "SECTION COUNT REPORT", titleStyle)
	_ = f.MergeCell(sheet, "A1", "F1")
	s.setValue(f, sheet, "G1", reportDate, dateStyle)

	// Metadata row.
	totalDevices := 0
	for _, section := range sections {
		totalDevices += section.Total
	}

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

	// Row 3 is the spacer.
	headers := []string{
		"Sr.No",
		"Section Name",
		"Total Device",
		"Beat Completed",
		"Beat Not Completed",
		"Device Off",
		"OverSpeed",
	}

	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
		}
		s.setValue(f, sheet, cell, header, headerStyle)
	}

	// Data rows start at row 5.
	totalCompleted, totalNotCompleted, totalOff, totalOverSpeed := 0, 0, 0, 0

	for i, section := range sections {
		row := i + 5
		if err := f.SetRowHeight(sheet, row, 30); err != nil {
			return nil, err
		}

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

		totalCompleted += section.Completed
		totalNotCompleted += section.NotCompleted
		totalOff += section.Off
		totalOverSpeed += section.OverSpeed

		values := []string{
			fmt.Sprint(i + 1),
			section.SectionName,
			fmt.Sprint(section.Total),
			fmt.Sprint(section.Completed),
			s.countWithNames(section.NotCompleted, section.NotCompletedNames),
			s.countWithNames(section.Off, section.OffNames),
			s.countWithNames(section.OverSpeed, section.OverSpeedNames),
		}

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

			// Section Name is bold teal
			styleID := styles[1]
			if col == 1 {
				styleID = styles[0]
			}
			s.setValue(f, sheet, cell, value, styleID)
		}
	}

	// Totals row.
	totalRow := len(sections) + 5
	if err := f.SetRowHeight(sheet, totalRow, 18); err != nil {
		return nil, err
	}

	totals := []string{
		"Total",
		fmt.Sprintf("%d Sections", len(sections)),
		fmt.Sprint(totalDevices),
		fmt.Sprint(totalCompleted),
		fmt.Sprint(totalNotCompleted),
		fmt.Sprint(totalOff),
		fmt.Sprint(totalOverSpeed),
	}

	for col, value := range totals {
		cell, err := excelize.CoordinatesToCellName(col+1, totalRow)
		if err != nil {
			return nil, err
		}
		s.setValue(f, sheet, cell, value, totalStyle)
	}

	var buf bytes.Buffer
	if err := f.Write(&buf); err != nil {
		return nil, fmt.Errorf("failed to generate Section Count report Excel: %w", err)
	}

	return buf.Bytes(), nil
}

// title and date share the same style, only the colour differs
func (s *SectionCountReportExcel) titleStyle(f *excelize.File, color string) (int, error) {
	return f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Family: "Arial", Size: 13, Bold: true, Color: color},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
	})
}

// [0] = section name cell (bold teal), [1] = normal cell
func (s *SectionCountReportExcel) dataRowStyles(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:   "top",
			WrapText:   true,
		},
		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:   "top",
			WrapText:   true,
		},
		Border: reportBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

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

func (s *SectionCountReportExcel) setValue(f *excelize.File, sheet, cell, value string, style int) {
	if value == "" {
		value = "-"
	}
	_ = f.SetCellValue(sheet, cell, value)
	_ = f.SetCellStyle(sheet, cell, cell, style)
}

func (s *SectionCountReportExcel) setMetaPair(
	f *excelize.File,
	sheet, labelCell, valueCell, label, value string,
	labelStyle, valueStyle int,
) {
	s.setValue(f, sheet, labelCell, label, labelStyle)
	s.setValue(f, sheet, valueCell, value, valueStyle)
}

// Shows count on first line, device names wrapped below. e.g. "3\nK/ASH-1, K/ASH-2, K/ASH-3"
func (s *SectionCountReportExcel) countWithNames(count int, names string) string {
	if count == 0 || strings.TrimSpace(names) == "" {
		return fmt.Sprint(count)
	}
	return fmt.Sprintf("%d\n%s", count, names)
}
