package linedb

import (
	"fmt"
	"os"
	"time"
)

// Transaction представляет транзакцию
type Transaction struct {
	transactionMode       string
	transactionID         string
	timeoutMs             int
	timeoutID             *time.Timer
	rollback              bool
	backupFile            string
	doNotDeleteBackupFile bool
	// mutex                 sync.RWMutex
	active bool
}

// NewTransaction создает новую транзакцию
func NewTransaction(mode string, id string, timeout int, rollback bool) *Transaction {
	tx := &Transaction{
		transactionMode: mode,
		transactionID:   id,
		timeoutMs:       timeout,
		rollback:        rollback,
		active:          true,
	}

	if timeout > 0 {
		tx.timeoutID = time.AfterFunc(time.Duration(timeout)*time.Millisecond, func() {
			tx.active = false
		})
	}

	return tx
}

// ClearTimeout очищает таймаут транзакции
func (t *Transaction) ClearTimeout() {
	if t.timeoutID != nil {
		t.timeoutID.Stop()
	}
}

// IsActive проверяет, является ли транзакция активной
func (t *Transaction) IsActive() bool {
	return t.active
}

// IsReadMode проверяет, является ли транзакция режимом чтения
func (t *Transaction) IsReadMode() bool {
	return t.transactionMode == "read"
}

// IsWriteMode проверяет, является ли транзакция режимом записи
func (t *Transaction) IsWriteMode() bool {
	return t.transactionMode == "write"
}

// ShouldRollback проверяет, требуется ли откат транзакции при ошибке
func (t *Transaction) ShouldRollback() bool {
	return t.rollback
}

// ShouldKeepBackup проверяет, нужно ли сохранять резервную копию
func (t *Transaction) ShouldKeepBackup() bool {
	return !t.doNotDeleteBackupFile
}

// GetBackupFile получает путь к файлу резервной копии
func (t *Transaction) GetBackupFile() string {
	return t.backupFile
}

// SetBackupFile устанавливает путь к файлу резервной копии
func (t *Transaction) SetBackupFile(path string) {
	t.backupFile = path
}

// CreateBackup создает резервную копию файла
func (t *Transaction) CreateBackup(filename string) error {
	if filename == "" {
		return fmt.Errorf("filename is required")
	}

	// Создаем резервную копию
	backupFile := filename + ".backup"

	// Копируем файл
	src, err := os.Open(filename)
	if err != nil {
		return fmt.Errorf("failed to open source file: %w", err)
	}
	defer src.Close()

	dst, err := os.Create(backupFile)
	if err != nil {
		return fmt.Errorf("failed to create backup file: %w", err)
	}
	defer dst.Close()

	_, err = dst.ReadFrom(src)
	if err != nil {
		return fmt.Errorf("failed to copy file: %w", err)
	}

	t.backupFile = backupFile
	return nil
}

// RestoreFromBackup восстанавливает из резервной копии
func (t *Transaction) RestoreFromBackup(filename string) error {
	if t.backupFile == "" {
		return fmt.Errorf("no backup file available")
	}

	// Копируем резервную копию обратно
	src, err := os.Open(t.backupFile)
	if err != nil {
		return fmt.Errorf("failed to open backup file: %w", err)
	}
	defer src.Close()

	dst, err := os.Create(filename)
	if err != nil {
		return fmt.Errorf("failed to create target file: %w", err)
	}
	defer dst.Close()

	_, err = dst.ReadFrom(src)
	if err != nil {
		return fmt.Errorf("failed to copy backup: %w", err)
	}

	return nil
}

// CleanupBackup удаляет резервную копию
func (t *Transaction) CleanupBackup() error {
	if t.backupFile != "" && !t.doNotDeleteBackupFile {
		return os.Remove(t.backupFile)
	}
	return nil
}
