package servicekalibrasi

import (
	"strings"
	"system-altrak/internal/domain"
	"system-altrak/internal/repository"

	"gorm.io/gorm"
)

type ServiceKalibrasiRepository interface {
	Create(kalibrasi *domain.MemoServiceKalibrasi) error
	Update(kalibrasi *domain.MemoServiceKalibrasi, branchID uint, role string) error
	GetByID(id uint, branchID uint, role string) (*domain.MemoServiceKalibrasi, error)
	List(branchID uint, role string) ([]domain.MemoServiceKalibrasi, error)
	GetNextSequence(docType string, year, month int) (int, error)
	Delete(id uint, branchID uint, role string) error
}

type repositoryImpl struct {
	base *repository.Repository
}

func NewRepository(base *repository.Repository) ServiceKalibrasiRepository {
	return &repositoryImpl{base: base}
}

func (r *repositoryImpl) Create(kalibrasi *domain.MemoServiceKalibrasi) error {
	return r.base.GetDB().Transaction(func(tx *gorm.DB) error {
		// Save the main record first, omitting associations to handle them manually.
		if err := tx.Omit("Checklist", "Equipments").Create(kalibrasi).Error; err != nil {
			return err
		}

		// Save the checklist manually, ensuring ID is 0 for auto-increment.
		if kalibrasi.Checklist != nil {
			kalibrasi.Checklist.ID = 0
			kalibrasi.Checklist.MemoServiceKalibrasiID = kalibrasi.ID
			if err := tx.Omit("ID").Create(kalibrasi.Checklist).Error; err != nil {
				return err
			}
		}

		// Save each equipment manually, ensuring ID is 0 for auto-increment.
		for i := range kalibrasi.Equipments {
			kalibrasi.Equipments[i].ID = 0
			kalibrasi.Equipments[i].MemoServiceKalibrasiID = kalibrasi.ID
			if err := tx.Omit("ID").Create(&kalibrasi.Equipments[i]).Error; err != nil {
				return err
			}
		}

		return nil
	})
}

func (r *repositoryImpl) Update(kalibrasi *domain.MemoServiceKalibrasi, branchID uint, role string) error {
	return r.base.GetDB().Transaction(func(tx *gorm.DB) error {
		var existing domain.MemoServiceKalibrasi
		query := tx.Where("id = ?", kalibrasi.ID)
		if role != "superadmin" && branchID > 0 {
			query = query.Where("branch_id = ?", branchID)
		}
		if err := query.First(&existing).Error; err != nil {
			return err
		}

		status := existing.Status
		if strings.TrimSpace(kalibrasi.Status) != "" {
			status = kalibrasi.Status
		}

		if err := tx.Model(&existing).Updates(map[string]interface{}{
			"charge_to":          kalibrasi.ChargeTo,
			"cc":                 kalibrasi.CC,
			"customer":           kalibrasi.Customer,
			"equipment_location": kalibrasi.EquipmentLocation,
			"sales_agreement_no": kalibrasi.SalesAgreementNo,
			"description":        kalibrasi.Description,
			"status":             status,
			"engine_unit":        kalibrasi.EngineUnit,
			"esn_number":         kalibrasi.ESNNumber,
			"component_name":     kalibrasi.ComponentName,
			"spv_name":           kalibrasi.SpvName,
			"spv_position":       kalibrasi.SpvPosition,
			"subject":            kalibrasi.Subject,
			"to":                 kalibrasi.To,
			"from":               kalibrasi.From,
		}).Error; err != nil {
			return err
		}

		if err := tx.Unscoped().Where("memo_service_kalibrasi_id = ?", existing.ID).Delete(&domain.MemoServiceKalibrasiChecklist{}).Error; err != nil {
			return err
		}
		if kalibrasi.Checklist != nil {
			kalibrasi.Checklist.ID = 0
			kalibrasi.Checklist.MemoServiceKalibrasiID = existing.ID
			if err := tx.Omit("ID").Create(kalibrasi.Checklist).Error; err != nil {
				return err
			}
		}

		if err := tx.Unscoped().Where("memo_service_kalibrasi_id = ?", existing.ID).Delete(&domain.MemoServiceKalibrasiEquipment{}).Error; err != nil {
			return err
		}
		for i := range kalibrasi.Equipments {
			kalibrasi.Equipments[i].ID = 0
			kalibrasi.Equipments[i].MemoServiceKalibrasiID = existing.ID
			if err := tx.Omit("ID").Create(&kalibrasi.Equipments[i]).Error; err != nil {
				return err
			}
		}
		return nil
	})
}

func (r *repositoryImpl) GetByID(id uint, branchID uint, role string) (*domain.MemoServiceKalibrasi, error) {
	var kalibrasi domain.MemoServiceKalibrasi
	q := r.base.GetDB().Preload("Checklist").Preload("Equipments")
	if role != "superadmin" && branchID > 0 {
		q = q.Where("branch_id = ?", branchID)
	}
	err := q.First(&kalibrasi, id).Error
	return &kalibrasi, err
}

func (r *repositoryImpl) List(branchID uint, role string) ([]domain.MemoServiceKalibrasi, error) {
	var list []domain.MemoServiceKalibrasi
	q := r.base.GetDB().Order("created_at desc")
	if role != "superadmin" && branchID > 0 {
		q = q.Where("branch_id = ?", branchID)
	}
	err := q.Find(&list).Error
	return list, err
}

func (r *repositoryImpl) GetNextSequence(docType string, year, month int) (int, error) {
	return r.base.GetNextSequence(docType, year, month)
}

func (r *repositoryImpl) Delete(id uint, branchID uint, role string) error {
	q := r.base.GetDB().Where("id = ?", id)
	if role != "superadmin" && branchID > 0 {
		q = q.Where("branch_id = ?", branchID)
	}
	return q.Delete(&domain.MemoServiceKalibrasi{}).Error
}
