package repository

import (
	"context"
	"eslogad-be/internal/entities"

	"github.com/google/uuid"
	"gorm.io/gorm"
)

// DocumentSessionRepository handles document session operations
type DocumentSessionRepository struct {
	db *gorm.DB
}

func NewDocumentSessionRepository(db *gorm.DB) *DocumentSessionRepository {
	return &DocumentSessionRepository{db: db}
}

func (r *DocumentSessionRepository) Create(ctx context.Context, session *entities.DocumentSession) error {
	db := DBFromContext(ctx, r.db)
	return db.WithContext(ctx).Create(session).Error
}

func (r *DocumentSessionRepository) GetByKey(ctx context.Context, documentKey string) (*entities.DocumentSession, error) {
	db := DBFromContext(ctx, r.db)
	var session entities.DocumentSession
	err := db.WithContext(ctx).
		Preload("User").
		Where("document_key = ?", documentKey).
		First(&session).Error
	if err != nil {
		return nil, err
	}
	return &session, nil
}

func (r *DocumentSessionRepository) GetActiveByDocument(ctx context.Context, documentID uuid.UUID) (*entities.DocumentSession, error) {
	db := DBFromContext(ctx, r.db)
	var session entities.DocumentSession
	err := db.WithContext(ctx).
		Preload("User").
		Where("document_id = ? AND status != 4", documentID). // Status 4 = closed
		Order("created_at DESC").
		First(&session).Error
	if err != nil {
		return nil, err
	}
	return &session, nil
}

func (r *DocumentSessionRepository) Update(ctx context.Context, session *entities.DocumentSession) error {
	db := DBFromContext(ctx, r.db)
	// Only update specific fields to avoid association issues
	updates := map[string]interface{}{
		"status":        session.Status,
		"is_locked":     session.IsLocked,
		"locked_by":     session.LockedBy,
		"locked_at":     session.LockedAt,
		"last_saved_at": session.LastSavedAt,
		"version":       session.Version,
		"updated_at":    session.UpdatedAt,
	}
	return db.WithContext(ctx).Model(&entities.DocumentSession{}).Where("id = ?", session.ID).Updates(updates).Error
}

func (r *DocumentSessionRepository) ListByDocument(ctx context.Context, documentID uuid.UUID) ([]entities.DocumentSession, error) {
	db := DBFromContext(ctx, r.db)
	var sessions []entities.DocumentSession
	err := db.WithContext(ctx).
		Preload("User").
		Where("document_id = ?", documentID).
		Order("created_at DESC").
		Find(&sessions).Error
	return sessions, err
}

// DocumentVersionRepository handles document version operations
type DocumentVersionRepository struct {
	db *gorm.DB
}

func NewDocumentVersionRepository(db *gorm.DB) *DocumentVersionRepository {
	return &DocumentVersionRepository{db: db}
}

func (r *DocumentVersionRepository) Create(ctx context.Context, version *entities.DocumentVersion) error {
	db := DBFromContext(ctx, r.db)
	return db.WithContext(ctx).Create(version).Error
}

func (r *DocumentVersionRepository) GetByID(ctx context.Context, id uuid.UUID) (*entities.DocumentVersion, error) {
	db := DBFromContext(ctx, r.db)
	var version entities.DocumentVersion
	err := db.WithContext(ctx).
		Preload("User").
		Where("id = ?", id).
		First(&version).Error
	if err != nil {
		return nil, err
	}
	return &version, nil
}

func (r *DocumentVersionRepository) GetActiveVersion(ctx context.Context, documentID uuid.UUID) (*entities.DocumentVersion, error) {
	db := DBFromContext(ctx, r.db)
	var version entities.DocumentVersion
	err := db.WithContext(ctx).
		Preload("User").
		Where("document_id = ? AND is_active = ?", documentID, true).
		First(&version).Error
	if err != nil {
		return nil, err
	}
	return &version, nil
}

func (r *DocumentVersionRepository) ListByDocument(ctx context.Context, documentID uuid.UUID) ([]entities.DocumentVersion, error) {
	db := DBFromContext(ctx, r.db)
	var versions []entities.DocumentVersion
	err := db.WithContext(ctx).
		Preload("User").
		Where("document_id = ?", documentID).
		Order("version DESC").
		Find(&versions).Error
	return versions, err
}

func (r *DocumentVersionRepository) DeactivateAllVersions(ctx context.Context, documentID uuid.UUID) error {
	db := DBFromContext(ctx, r.db)
	return db.WithContext(ctx).
		Model(&entities.DocumentVersion{}).
		Where("document_id = ?", documentID).
		Update("is_active", false).Error
}

// DocumentMetadataRepository handles document metadata operations
type DocumentMetadataRepository struct {
	db *gorm.DB
}

func NewDocumentMetadataRepository(db *gorm.DB) *DocumentMetadataRepository {
	return &DocumentMetadataRepository{db: db}
}

func (r *DocumentMetadataRepository) Create(ctx context.Context, metadata *entities.DocumentMetadata) error {
	db := DBFromContext(ctx, r.db)
	return db.WithContext(ctx).Create(metadata).Error
}

func (r *DocumentMetadataRepository) GetByDocumentID(ctx context.Context, documentID uuid.UUID) (*entities.DocumentMetadata, error) {
	db := DBFromContext(ctx, r.db)
	var metadata entities.DocumentMetadata
	err := db.WithContext(ctx).
		Where("document_id = ?", documentID).
		First(&metadata).Error
	if err != nil {
		return nil, err
	}
	return &metadata, nil
}

func (r *DocumentMetadataRepository) Update(ctx context.Context, metadata *entities.DocumentMetadata) error {
	db := DBFromContext(ctx, r.db)
	// Only update specific fields to avoid association issues
	updates := map[string]interface{}{
		"document_type": metadata.DocumentType,
		"reference_id":  metadata.ReferenceID,
		"file_name":     metadata.FileName,
		"file_type":     metadata.FileType,
		"file_size":     metadata.FileSize,
		"mime_type":     metadata.MimeType,
		"updated_at":    metadata.UpdatedAt,
	}
	return db.WithContext(ctx).Model(&entities.DocumentMetadata{}).Where("id = ?", metadata.ID).Updates(updates).Error
}

func (r *DocumentMetadataRepository) Delete(ctx context.Context, documentID uuid.UUID) error {
	db := DBFromContext(ctx, r.db)
	return db.WithContext(ctx).
		Where("document_id = ?", documentID).
		Delete(&entities.DocumentMetadata{}).Error
}

// DocumentErrorRepository handles document error logging
type DocumentErrorRepository struct {
	db *gorm.DB
}

func NewDocumentErrorRepository(db *gorm.DB) *DocumentErrorRepository {
	return &DocumentErrorRepository{db: db}
}

func (r *DocumentErrorRepository) Create(ctx context.Context, docError *entities.DocumentError) error {
	db := DBFromContext(ctx, r.db)
	return db.WithContext(ctx).Create(docError).Error
}

func (r *DocumentErrorRepository) ListByDocument(ctx context.Context, documentID uuid.UUID) ([]entities.DocumentError, error) {
	db := DBFromContext(ctx, r.db)
	var errors []entities.DocumentError
	err := db.WithContext(ctx).
		Preload("Session").
		Where("document_id = ?", documentID).
		Order("created_at DESC").
		Find(&errors).Error
	return errors, err
}

func (r *DocumentErrorRepository) ListBySession(ctx context.Context, sessionID uuid.UUID) ([]entities.DocumentError, error) {
	db := DBFromContext(ctx, r.db)
	var errors []entities.DocumentError
	err := db.WithContext(ctx).
		Where("session_id = ?", sessionID).
		Order("created_at DESC").
		Find(&errors).Error
	return errors, err
}