package db

import (
	"database/sql"
	"fmt"
	"time"
)

// SyncMetadata represents sync tracking information
type SyncMetadata struct {
	ID             int64
	EntityType     string
	LastSyncAt     time.Time
	RecordsUpdated int
	RecordsFailed  int
	Status         string
	ErrorMessage   string
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

// SyncStore handles sync metadata operations
type SyncStore struct {
	db *DB
}

// NewSyncStore creates a new sync store
func NewSyncStore(db *DB) *SyncStore {
	return &SyncStore{db: db}
}

// GetLastSync retrieves the last sync metadata for an entity type
func (s *SyncStore) GetLastSync(entityType string) (*SyncMetadata, error) {
	var meta SyncMetadata
	var lastSyncAt, createdAt, updatedAt string
	var errorMessage sql.NullString

	err := s.db.conn.QueryRow(`
		SELECT id, entity_type, last_sync_at, records_updated, records_failed,
		       status, COALESCE(error_message, ''), created_at, updated_at
		FROM sync_metadata
		WHERE entity_type = ?
	`, entityType).Scan(
		&meta.ID, &meta.EntityType, &lastSyncAt, &meta.RecordsUpdated,
		&meta.RecordsFailed, &meta.Status, &errorMessage, &createdAt, &updatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil // No sync record found
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get sync metadata: %w", err)
	}

	meta.LastSyncAt, _ = time.Parse(time.RFC3339, lastSyncAt)
	meta.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
	meta.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)
	meta.ErrorMessage = errorMessage.String

	return &meta, nil
}

// CanSync checks if enough time has passed since last sync
func (s *SyncStore) CanSync(entityType string, minInterval time.Duration) (bool, time.Time, error) {
	meta, err := s.GetLastSync(entityType)
	if err != nil {
		return false, time.Time{}, err
	}

	// No previous sync
	if meta == nil {
		return true, time.Time{}, nil
	}

	// Check if minimum interval has passed
	nextAllowed := meta.LastSyncAt.Add(minInterval)
	if time.Now().Before(nextAllowed) {
		return false, nextAllowed, nil
	}

	return true, time.Time{}, nil
}

// RecordSyncStart records the start of a sync operation
func (s *SyncStore) RecordSyncStart(entityType string) error {
	now := time.Now()

	_, err := s.db.conn.Exec(`
		INSERT INTO sync_metadata (entity_type, last_sync_at, status, records_updated, records_failed, created_at, updated_at)
		VALUES (?, ?, 'running', 0, 0, ?, ?)
		ON CONFLICT(entity_type) DO UPDATE SET
			last_sync_at = excluded.last_sync_at,
			status = 'running',
			records_updated = 0,
			records_failed = 0,
			error_message = NULL,
			updated_at = excluded.updated_at
	`, entityType, now.Format(time.RFC3339), now.Format(time.RFC3339), now.Format(time.RFC3339))

	if err != nil {
		return fmt.Errorf("failed to record sync start: %w", err)
	}

	return nil
}

// RecordSyncComplete records the completion of a sync operation
func (s *SyncStore) RecordSyncComplete(entityType string, updated, failed int, errMsg string) error {
	now := time.Now()
	status := "completed"
	if failed > 0 {
		status = "completed_with_errors"
	}

	var errorMessage *string
	if errMsg != "" {
		errorMessage = &errMsg
	}

	_, err := s.db.conn.Exec(`
		UPDATE sync_metadata
		SET status = ?,
		    records_updated = ?,
		    records_failed = ?,
		    error_message = ?,
		    updated_at = ?
		WHERE entity_type = ?
	`, status, updated, failed, errorMessage, now.Format(time.RFC3339), entityType)

	if err != nil {
		return fmt.Errorf("failed to record sync completion: %w", err)
	}

	return nil
}

// RecordSyncError records a sync operation failure
func (s *SyncStore) RecordSyncError(entityType string, errMsg string) error {
	now := time.Now()

	_, err := s.db.conn.Exec(`
		UPDATE sync_metadata
		SET status = 'failed',
		    error_message = ?,
		    updated_at = ?
		WHERE entity_type = ?
	`, errMsg, now.Format(time.RFC3339), entityType)

	if err != nil {
		return fmt.Errorf("failed to record sync error: %w", err)
	}

	return nil
}

// GetAllSyncStatus retrieves sync status for all entity types
func (s *SyncStore) GetAllSyncStatus() ([]SyncMetadata, error) {
	rows, err := s.db.conn.Query(`
		SELECT id, entity_type, last_sync_at, records_updated, records_failed,
		       status, COALESCE(error_message, ''), created_at, updated_at
		FROM sync_metadata
		ORDER BY entity_type
	`)
	if err != nil {
		return nil, fmt.Errorf("failed to get sync status: %w", err)
	}
	defer rows.Close()

	var results []SyncMetadata
	for rows.Next() {
		var meta SyncMetadata
		var lastSyncAt, createdAt, updatedAt string
		var errorMessage sql.NullString

		err := rows.Scan(
			&meta.ID, &meta.EntityType, &lastSyncAt, &meta.RecordsUpdated,
			&meta.RecordsFailed, &meta.Status, &errorMessage, &createdAt, &updatedAt,
		)
		if err != nil {
			return nil, fmt.Errorf("failed to scan sync metadata: %w", err)
		}

		meta.LastSyncAt, _ = time.Parse(time.RFC3339, lastSyncAt)
		meta.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
		meta.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)
		meta.ErrorMessage = errorMessage.String

		results = append(results, meta)
	}

	return results, nil
}
