package mysql

import (
	"context"
	"errors"
	"time"

	"gorm.io/gorm"

	filemanager "wucher/internal/domain/file_manager"
	helicopterfile "wucher/internal/domain/helicopter_file"
	takeover "wucher/internal/domain/takeover"
)

type TakeoverRepository struct {
	db *gorm.DB
}

func NewTakeoverRepository(db *gorm.DB) *TakeoverRepository {
	return &TakeoverRepository{db: db}
}

func (r *TakeoverRepository) Create(ctx context.Context, row *takeover.TakeoverAc) error {
	return r.db.WithContext(ctx).Create(row).Error
}

func (r *TakeoverRepository) Update(ctx context.Context, row *takeover.TakeoverAc) error {
	return r.db.WithContext(ctx).Save(row).Error
}

func (r *TakeoverRepository) Delete(ctx context.Context, id []byte, deletedBy []byte) error {
	now := time.Now().UTC()
	return r.db.WithContext(ctx).Model(&takeover.TakeoverAc{}).
		Where("id = ? AND deleted_at IS NULL", id).
		Updates(map[string]any{"deleted_at": now, "deleted_by": deletedBy, "updated_by": deletedBy}).Error
}

// ListActiveEditedTemplateUUIDs returns template UUIDs for takeover-linked files
// that are still active. Trashed or lifecycle-deleted files are ignored.
func (r *TakeoverRepository) ListActiveEditedTemplateUUIDs(tx *gorm.DB, takeoverID []byte) ([][]byte, error) {
	if len(takeoverID) != 16 {
		return nil, nil
	}
	db := tx
	if db == nil {
		db = r.db
	}
	var editedTemplateUUIDs [][]byte
	if err := db.Table("file_files").
		Where(
			"takeover_id = ? AND template_uuid IS NOT NULL AND deleted_at IS NULL AND lifecycle_deleted_at IS NULL AND status <> ?",
			takeoverID,
			filemanager.FileStatusTrashed,
		).
		Distinct().
		Pluck("template_uuid", &editedTemplateUUIDs).Error; err != nil {
		return nil, err
	}
	return editedTemplateUUIDs, nil
}

// ListChecklistTemplateFiles returns the helicopter files that make up a section's
// inspection checklist. Documents created from a template (via create-from-template)
// are stored as helicopter_files rows for takeover/WOPI editing but are not checklist
// items, so they are excluded here. Pass the active transaction handle to run within
// an ongoing transaction; when tx is nil the repository's own connection is used.
func (r *TakeoverRepository) ListChecklistTemplateFiles(tx *gorm.DB, helicopterID []byte, section string) ([]helicopterfile.HelicopterFile, error) {
	db := tx
	if db == nil {
		db = r.db
	}
	var rows []helicopterfile.HelicopterFile
	if err := db.
		Model(&helicopterfile.HelicopterFile{}).
		Preload("SourceFile").
		Preload("FileAttachment").
		Preload("FileAttachment.File").
		Where("helicopter_id = ? AND section = ?", helicopterID, section).
		Order("position ASC, id ASC").
		Find(&rows).Error; err != nil {
		return nil, err
	}
	filtered := rows[:0]
	for i := range rows {
		if helicopterFileRowCreatedFromTemplate(&rows[i]) {
			continue
		}
		filtered = append(filtered, rows[i])
	}
	return filtered, nil
}

// helicopterFileRowCreatedFromTemplate reports whether a helicopter file row points to a
// document instantiated from a template (non-empty template_uuid on the underlying file).
func helicopterFileRowCreatedFromTemplate(row *helicopterfile.HelicopterFile) bool {
	if row == nil {
		return false
	}
	if row.SourceFile != nil {
		return len(row.SourceFile.TemplateUUID) == 16
	}
	if row.FileAttachment != nil && row.FileAttachment.File != nil {
		return len(row.FileAttachment.File.TemplateUUID) == 16
	}
	return false
}

func (r *TakeoverRepository) GetByID(ctx context.Context, id []byte) (*takeover.TakeoverAc, error) {
	var row takeover.TakeoverAc
	err := r.db.WithContext(ctx).
		Preload("Base").
		Preload("ReserveAc").
		Preload("ReserveAc.Aircraft").
		Preload("ReserveAc.Inspection").
		Preload("RosterCrews").
		Preload("OtherPeople").
		Preload("Files").
		Preload("Files.FileAttachment").
		Preload("Files.FileAttachment.File").
		Where("id = ? AND deleted_at IS NULL", id).
		First(&row).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		return nil, nil
	}
	return &row, err
}

func (r *TakeoverRepository) List(ctx context.Context, limit, offset int) ([]takeover.TakeoverAc, int64, error) {
	rows := make([]takeover.TakeoverAc, 0)
	var total int64
	base := r.db.WithContext(ctx).
		Model(&takeover.TakeoverAc{}).
		Preload("Base").
		Preload("ReserveAc").
		Preload("ReserveAc.Aircraft").
		Preload("ReserveAc.Inspection").
		Preload("RosterCrews").
		Preload("OtherPeople").
		Preload("Files").
		Preload("Files.FileAttachment").
		Preload("Files.FileAttachment.File").
		Where("deleted_at IS NULL")
	if err := base.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	q := base.Order("created_at DESC")
	if limit > 0 {
		q = q.Limit(limit).Offset(offset)
	}
	if err := q.Find(&rows).Error; err != nil {
		return nil, 0, err
	}
	return rows, total, nil
}
