package sjr

import (
	"fmt"
	"strings"
	"system-altrak/internal/domain"
	"system-altrak/internal/dto"
	setModule "system-altrak/internal/modules/setting"
	"system-altrak/pkg/utils"
	"time"

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

type SJRService interface {
	CreateAuthorization(req *dto.ServiceJobRequestDTO, userID, branchID uint) (*domain.ServiceAuthorization, error)
	UpdateAuthorization(id uint, req *dto.ServiceJobRequestDTO, branchID uint, role string) (*domain.ServiceAuthorization, error)
	GetAuthorizationByID(id uint, branchID uint, role string) (*domain.ServiceAuthorization, error)
	ListAuthorizations(branchID uint, role string) ([]domain.ServiceAuthorization, error)
	SynthesizePDF(id uint, branchID uint, role string) ([]byte, string, error)
	ExportExcel(branchID uint, role string, requestType string) ([]byte, error)
	Delete(id uint, branchID uint, role string) error
}

type serviceImpl struct {
	repo    SJRRepository
	pdf     *utils.PdfGenerator
	setting setModule.SettingService
}

func NewService(repo SJRRepository, pdf *utils.PdfGenerator, setting ...setModule.SettingService) SJRService {
	var resolvedSetting setModule.SettingService
	if len(setting) > 0 {
		resolvedSetting = setting[0]
	}

	return &serviceImpl{repo: repo, pdf: pdf, setting: resolvedSetting}
}

func (s *serviceImpl) CreateAuthorization(req *dto.ServiceJobRequestDTO, userID, branchID uint) (*domain.ServiceAuthorization, error) {
	now := time.Now()
	year := now.Year()
	month := int(now.Month())

	// Sequence synchronization protocol
	seq, err := s.repo.FetchSerialSequence("SJR", year, month)
	if err != nil {
		return nil, fmt.Errorf("failed to synchronize serial sequence: %v", err)
	}

	romanMonth := utils.GetRomanMonth(month)
	shortYear := year % 100
	ref := fmt.Sprintf("%03d/SJR-BJM/%s/%02d", seq, romanMonth, shortYear)

	reqType := req.RequestType
	if reqType == "" {
		reqType = "repair"
	}

	toDept := req.ToDepartment
	if toDept == "" {
		toDept = "Service Operations – PT.A Banjarmasin Hub"
	}
	fromDept := req.FromDepartment
	if fromDept == "" {
		fromDept = "Inventory Assets – PT.A Banjarmasin Hub"
	}
	signedBy := req.SignedBy
	if signedBy == "" {
		signedBy = "Authorized Supervisor"
	}
	signedTitle := req.SignedTitle
	if signedTitle == "" {
		signedTitle = "OPERATIONAL SPV"
	}

	auth := &domain.ServiceAuthorization{
		Ref:            ref,
		Date:           now,
		RequestType:    reqType,
		CustomerName:   req.CustomerName,
		JobName:        req.JobName,
		Component:      req.Component,
		EngineBrand:    req.EngineBrand,
		EngineModel:    req.EngineModel,
		ESN:            req.ESN,
		ToDepartment:   toDept,
		FromDepartment: fromDept,
		SignedBy:       signedBy,
		SignedTitle:    signedTitle,
		Status:         "DRAFT",
		CreatedBy:      &userID,
		BranchID:       branchID,
	}

	if err := s.repo.CreateAuthorization(auth); err != nil {
		return nil, err
	}
	return auth, nil
}

func (s *serviceImpl) UpdateAuthorization(id uint, req *dto.ServiceJobRequestDTO, branchID uint, role string) (*domain.ServiceAuthorization, error) {
	auth, err := s.repo.GetAuthorizationByID(id, branchID, role)
	if err != nil {
		return nil, err
	}

	reqType := req.RequestType
	if reqType == "" {
		reqType = auth.RequestType
	}
	if reqType == "" {
		reqType = "repair"
	}

	auth.RequestType = reqType
	auth.CustomerName = req.CustomerName
	auth.JobName = req.JobName
	auth.Component = req.Component
	auth.EngineBrand = req.EngineBrand
	auth.EngineModel = req.EngineModel
	auth.ESN = req.ESN
	
	if req.ToDepartment != "" {
		auth.ToDepartment = req.ToDepartment
	} else if auth.ToDepartment == "" {
		auth.ToDepartment = "Service Operations – PT.A Banjarmasin Hub"
	}
	
	if req.FromDepartment != "" {
		auth.FromDepartment = req.FromDepartment
	} else if auth.FromDepartment == "" {
		auth.FromDepartment = "Inventory Assets – PT.A Banjarmasin Hub"
	}
	
	if req.SignedBy != "" {
		auth.SignedBy = req.SignedBy
	} else if auth.SignedBy == "" {
		auth.SignedBy = "Authorized Supervisor"
	}
	
	if req.SignedTitle != "" {
		auth.SignedTitle = req.SignedTitle
	} else if auth.SignedTitle == "" {
		auth.SignedTitle = "OPERATIONAL SPV"
	}
	auth.RevisionNumber++

	if err := s.repo.UpdateAuthorization(auth); err != nil {
		return nil, err
	}
	return auth, nil
}

func (s *serviceImpl) GetAuthorizationByID(id uint, branchID uint, role string) (*domain.ServiceAuthorization, error) {
	return s.repo.GetAuthorizationByID(id, branchID, role)
}

func (s *serviceImpl) ListAuthorizations(branchID uint, role string) ([]domain.ServiceAuthorization, error) {
	return s.repo.ListAuthorizations(branchID, role)
}

func (s *serviceImpl) SynthesizePDF(id uint, branchID uint, role string) ([]byte, string, error) {
	auth, err := s.repo.GetAuthorizationByID(id, branchID, role)
	if err != nil {
		return nil, "", err
	}

	months := []string{"", "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"}
	dateStr := fmt.Sprintf("%02d %s %04d", auth.Date.Day(), months[int(auth.Date.Month())], auth.Date.Year())

	var subject, bodyText string
	if auth.RequestType == "calibration" {
		subject = fmt.Sprintf("Operational Request: Calibration for %s %s, Engine %s (Model %s), ESN: %s", auth.JobName, auth.Component, auth.EngineBrand, auth.EngineModel, auth.ESN)
		bodyText = fmt.Sprintf("Based on the technical requirements for customer %s regarding the calibration of %s %s, Engine %s model %s (ESN: %s), we hereby request authorization to transport the component to PT. ALTRAK1978 Jakarta Headquarters for specialized calibration procedures.",
			auth.CustomerName, auth.JobName, auth.Component, auth.EngineBrand, auth.EngineModel, auth.ESN)
	} else {
		subject = fmt.Sprintf("Operational Request: Service Authorization for %s, Engine %s (Model %s), ESN: %s", auth.JobName, auth.EngineBrand, auth.EngineModel, auth.ESN)
		bodyText = fmt.Sprintf("Following the service request from customer %s for the maintenance of %s involving Engine %s model %s (ESN: %s), we request that a formal service job be initialized so that the technical team at PT. Altrak1978 Banjarmasin Hub can proceed with the required repairs.",
			auth.CustomerName, auth.JobName, auth.EngineBrand, auth.EngineModel, auth.ESN)
	}

	data := map[string]interface{}{
		"Header": map[string]interface{}{
			"Title": "INTER OFFICE MEMORANDUM",
			"Ref":   auth.Ref,
		},
		"Ref":            auth.Ref,
		"Date":           dateStr,
		"To":             auth.ToDepartment,
		"From":           auth.FromDepartment,
		"Subject":        subject,
		"CustomerName":   auth.CustomerName,
		"JobName":        auth.JobName,
		"SpecPart":       auth.Component,
		"EngineBrand":    auth.EngineBrand,
		"EngineModel":    auth.EngineModel,
		"JobDetail":      fmt.Sprintf("%s %s", auth.JobName, auth.Component),
		"Esn":            auth.ESN,
		"IsService":      auth.RequestType != "calibration",
		"IsCalibration":  auth.RequestType == "calibration",
		"SignatureName":  auth.SignedBy,
		"SignatureTitle": auth.SignedTitle,
		"BodyText":       bodyText,
	}

	helper := utils.NewExportHelper(s.pdf, s.setting)
	templateName := "iom/service_calibration_pdf.html"
	if auth.RequestType != "calibration" {
		templateName = "iom/service_part_pdf.html"
	}

	buf, err := helper.GenerateStandardPDF(templateName, data)
	if err != nil {
		return nil, "", err
	}

	return buf, auth.Ref, nil
}

func (s *serviceImpl) ExportExcel(branchID uint, role string, requestType string) ([]byte, error) {
	list, err := s.repo.ListAuthorizations(branchID, role)
	if err != nil {
		return nil, err
	}

	if requestType != "" {
		filtered := make([]domain.ServiceAuthorization, 0, len(list))
		for _, item := range list {
			if strings.EqualFold(strings.TrimSpace(item.RequestType), requestType) {
				filtered = append(filtered, item)
			}
		}
		list = filtered
	}

	f := excelize.NewFile()
	defer f.Close()

	sheet := "ServiceJobRegistry"
	f.SetSheetName("Sheet1", sheet)

	headers := []string{"Reference", "Date", "Phase", "Customer", "Job Specification", "Component", "Engine Brand", "Engine Model", "Serial Number (ESN)", "Node Status"}
	for i, h := range headers {
		cell, _ := excelize.CoordinatesToCellName(i+1, 1)
		f.SetCellValue(sheet, cell, h)
	}

	for i, item := range list {
		row := i + 2
		f.SetCellValue(sheet, fmt.Sprintf("A%d", row), item.Ref)
		f.SetCellValue(sheet, fmt.Sprintf("B%d", row), item.Date.Format("2006-01-02"))
		f.SetCellValue(sheet, fmt.Sprintf("C%d", row), item.RequestType)
		f.SetCellValue(sheet, fmt.Sprintf("D%d", row), item.CustomerName)
		f.SetCellValue(sheet, fmt.Sprintf("E%d", row), item.JobName)
		f.SetCellValue(sheet, fmt.Sprintf("F%d", row), item.Component)
		f.SetCellValue(sheet, fmt.Sprintf("G%d", row), item.EngineBrand)
		f.SetCellValue(sheet, fmt.Sprintf("H%d", row), item.EngineModel)
		f.SetCellValue(sheet, fmt.Sprintf("I%d", row), item.ESN)
		f.SetCellValue(sheet, fmt.Sprintf("J%d", row), item.Status)
	}

	buf, err := f.WriteToBuffer()
	if err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (s *serviceImpl) Delete(id uint, branchID uint, role string) error {
	return s.repo.DeleteRecord(id, branchID, role)
}
