package db

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

	"git.leaktechnologies.dev/stu/Goondex/internal/model"
)

// StudioStore handles CRUD operations for studios
type StudioStore struct {
	db *DB
}

// NewStudioStore creates a new studio store
func NewStudioStore(db *DB) *StudioStore {
	return &StudioStore{db: db}
}

// Create inserts a new studio
func (s *StudioStore) Create(studio *model.Studio) error {
	now := time.Now()
	studio.CreatedAt = now
	studio.UpdatedAt = now

	result, err := s.db.conn.Exec(`
		INSERT INTO studios (name, parent_id, image_path, image_url, description, source, source_id, created_at, updated_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
	`, studio.Name, studio.ParentID, studio.ImagePath, studio.ImageURL, studio.Description, studio.Source, studio.SourceID, studio.CreatedAt.Format(time.RFC3339), studio.UpdatedAt.Format(time.RFC3339))

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

	id, err := result.LastInsertId()
	if err != nil {
		return fmt.Errorf("failed to get last insert id: %w", err)
	}

	studio.ID = id
	return nil
}

// GetByID retrieves a studio by ID
func (s *StudioStore) GetByID(id int64) (*model.Studio, error) {
	studio := &model.Studio{}
	var createdAt, updatedAt string

	err := s.db.conn.QueryRow(`
		SELECT id, name, COALESCE(parent_id, 0), COALESCE(image_path, ''), COALESCE(image_url, ''), COALESCE(description, ''), COALESCE(source, ''), COALESCE(source_id, ''), created_at, updated_at
		FROM studios WHERE id = ?
	`, id).Scan(&studio.ID, &studio.Name, &studio.ParentID, &studio.ImagePath, &studio.ImageURL, &studio.Description, &studio.Source, &studio.SourceID, &createdAt, &updatedAt)

	if err == sql.ErrNoRows {
		return nil, fmt.Errorf("studio not found")
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get studio: %w", err)
	}

	studio.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
	studio.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)

	return studio, nil
}

// Search searches for studios by name
func (s *StudioStore) Search(query string) ([]model.Studio, error) {
	rows, err := s.db.conn.Query(`
		SELECT id, name, COALESCE(parent_id, 0), COALESCE(image_path, ''), COALESCE(image_url, ''), COALESCE(description, ''), COALESCE(source, ''), COALESCE(source_id, ''), created_at, updated_at
		FROM studios
		WHERE name LIKE ?
		ORDER BY name
	`, "%"+query+"%")

	if err != nil {
		return nil, fmt.Errorf("failed to search studios: %w", err)
	}
	defer rows.Close()

	var studios []model.Studio
	for rows.Next() {
		var studio model.Studio
		var createdAt, updatedAt string

		err := rows.Scan(&studio.ID, &studio.Name, &studio.ParentID, &studio.ImagePath, &studio.ImageURL, &studio.Description, &studio.Source, &studio.SourceID, &createdAt, &updatedAt)
		if err != nil {
			return nil, fmt.Errorf("failed to scan studio: %w", err)
		}

		studio.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
		studio.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)

		studios = append(studios, studio)
	}

	return studios, nil
}

// Update updates an existing studio
func (s *StudioStore) Update(studio *model.Studio) error {
	studio.UpdatedAt = time.Now()

	result, err := s.db.conn.Exec(`
		UPDATE studios
		SET name = ?, parent_id = ?, image_path = ?, image_url = ?, description = ?, source = ?, source_id = ?, updated_at = ?
		WHERE id = ?
	`, studio.Name, studio.ParentID, studio.ImagePath, studio.ImageURL, studio.Description, studio.Source, studio.SourceID, studio.UpdatedAt.Format(time.RFC3339), studio.ID)

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

	rows, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("failed to get rows affected: %w", err)
	}

	if rows == 0 {
		return fmt.Errorf("studio not found")
	}

	return nil
}

// GetSceneCount returns the number of scenes associated with a studio
func (s *StudioStore) GetSceneCount(studioID int64) (int, error) {
	var count int
	err := s.db.conn.QueryRow(`
		SELECT COUNT(*) FROM scenes WHERE studio_id = ?
	`, studioID).Scan(&count)

	if err != nil {
		return 0, fmt.Errorf("failed to count scenes: %w", err)
	}

	return count, nil
}

// Delete deletes a studio by ID
func (s *StudioStore) Delete(id int64) error {
	result, err := s.db.conn.Exec("DELETE FROM studios WHERE id = ?", id)
	if err != nil {
		return fmt.Errorf("failed to delete studio: %w", err)
	}

	rows, err := result.RowsAffected()
	if err != nil {
		return fmt.Errorf("failed to get rows affected: %w", err)
	}

	if rows == 0 {
		return fmt.Errorf("studio not found")
	}

	return nil
}

// Upsert inserts or updates a studio based on source_id
func (s *StudioStore) Upsert(st *model.Studio) error {
	// Try to find existing studio by source_id
	existing, err := s.GetBySourceID(st.Source, st.SourceID)
	if err == nil && existing != nil {
		// Update existing
		st.ID = existing.ID
		return s.Update(st)
	}
	// Create new
	return s.Create(st)
}

// GetBySourceID retrieves a studio by its source and source_id
func (s *StudioStore) GetBySourceID(source, sourceID string) (*model.Studio, error) {
	var st model.Studio
	var createdAt, updatedAt string

	err := s.db.conn.QueryRow(`
		SELECT id, name, COALESCE(parent_id, 0), COALESCE(image_path, ''), COALESCE(image_url, ''),
			COALESCE(description, ''), COALESCE(source, ''), COALESCE(source_id, ''),
			created_at, updated_at
		FROM studios
		WHERE source = ? AND source_id = ?
	`, source, sourceID).Scan(
		&st.ID, &st.Name, &st.ParentID, &st.ImagePath, &st.ImageURL,
		&st.Description, &st.Source, &st.SourceID,
		&createdAt, &updatedAt,
	)

	if err == sql.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		return nil, fmt.Errorf("failed to get studio: %w", err)
	}

	st.CreatedAt, _ = time.Parse(time.RFC3339, createdAt)
	st.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt)

	return &st, nil
}
