package store

import (
	"database/sql"
	"time"

	_ "modernc.org/sqlite"
)

type User struct {
	ID            int64
	Email         string
	PasswordHash  string
	PodcastTitle  string
	PodcastSlug   string
	PodcastImage  string
	PodcastAuthor string
	CreatedAt     time.Time
}

type Episode struct {
	ID          int64
	UserID      int64
	Title       string
	Description string
	AudioPath   string
	ImagePath   string
	PublishedAt time.Time
	CreatedAt   time.Time
}

type Store struct {
	db *sql.DB
}

func New(path string) (*Store, error) {
	db, err := sql.Open("sqlite", path)
	if err != nil {
		return nil, err
	}
	db.SetMaxOpenConns(1)

	if err := migrate(db); err != nil {
		return nil, err
	}

	return &Store{db: db}, nil
}

func migrate(db *sql.DB) error {
	schema := `
	CREATE TABLE IF NOT EXISTS users (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		email TEXT NOT NULL UNIQUE,
		password_hash TEXT NOT NULL,
		podcast_title TEXT NOT NULL DEFAULT '',
		podcast_slug TEXT NOT NULL DEFAULT '',
		podcast_image TEXT NOT NULL DEFAULT '',
		podcast_author TEXT NOT NULL DEFAULT '',
		created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
	);

	CREATE TABLE IF NOT EXISTS episodes (
		id INTEGER PRIMARY KEY AUTOINCREMENT,
		user_id INTEGER NOT NULL REFERENCES users(id),
		title TEXT NOT NULL,
		description TEXT NOT NULL DEFAULT '',
		audio_path TEXT NOT NULL DEFAULT '',
		image_path TEXT NOT NULL DEFAULT '',
		published_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
	);
	`
	_, err := db.Exec(schema)
	return err
}

func (s *Store) Close() error {
	return s.db.Close()
}

// --- Users ---

func (s *Store) UserCount() (int, error) {
	var n int
	err := s.db.QueryRow("SELECT COUNT(*) FROM users").Scan(&n)
	return n, err
}

func (s *Store) CreateUser(email, passwordHash string) (int64, error) {
	res, err := s.db.Exec("INSERT INTO users (email, password_hash) VALUES (?, ?)", email, passwordHash)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

func (s *Store) UserByEmail(email string) (*User, error) {
	u := &User{}
	err := s.db.QueryRow("SELECT id, email, password_hash, podcast_title, podcast_slug, podcast_image, podcast_author, created_at FROM users WHERE email = ?", email).
		Scan(&u.ID, &u.Email, &u.PasswordHash, &u.PodcastTitle, &u.PodcastSlug, &u.PodcastImage, &u.PodcastAuthor, &u.CreatedAt)
	if err != nil {
		return nil, err
	}
	return u, nil
}

func (s *Store) GetUser(id int64) (*User, error) {
	u := &User{}
	err := s.db.QueryRow("SELECT id, email, password_hash, podcast_title, podcast_slug, podcast_image, podcast_author, created_at FROM users WHERE id = ?", id).
		Scan(&u.ID, &u.Email, &u.PasswordHash, &u.PodcastTitle, &u.PodcastSlug, &u.PodcastImage, &u.PodcastAuthor, &u.CreatedAt)
	if err != nil {
		return nil, err
	}
	return u, nil
}

func (s *Store) UserBySlug(slug string) (*User, error) {
	u := &User{}
	err := s.db.QueryRow("SELECT id, email, password_hash, podcast_title, podcast_slug, podcast_image, podcast_author, created_at FROM users WHERE podcast_slug = ?", slug).
		Scan(&u.ID, &u.Email, &u.PasswordHash, &u.PodcastTitle, &u.PodcastSlug, &u.PodcastImage, &u.PodcastAuthor, &u.CreatedAt)
	if err != nil {
		return nil, err
	}
	return u, nil
}

func (s *Store) SlugTaken(slug string, excludeUserID int64) (bool, error) {
	var id int64
	err := s.db.QueryRow("SELECT id FROM users WHERE podcast_slug = ? AND id != ?", slug, excludeUserID).Scan(&id)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	return true, nil
}

func (s *Store) UpdateUserPodcast(id int64, title, slug, image, author string) error {
	_, err := s.db.Exec("UPDATE users SET podcast_title=?, podcast_slug=?, podcast_image=?, podcast_author=? WHERE id=?",
		title, slug, image, author, id)
	return err
}

// --- Episodes ---

func (s *Store) ListEpisodes(userID int64) ([]Episode, error) {
	rows, err := s.db.Query("SELECT id, user_id, title, description, audio_path, image_path, published_at, created_at FROM episodes WHERE user_id = ? ORDER BY published_at DESC", userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var eps []Episode
	for rows.Next() {
		var e Episode
		if err := rows.Scan(&e.ID, &e.UserID, &e.Title, &e.Description, &e.AudioPath, &e.ImagePath, &e.PublishedAt, &e.CreatedAt); err != nil {
			return nil, err
		}
		eps = append(eps, e)
	}
	return eps, rows.Err()
}

func (s *Store) GetEpisode(id int64) (*Episode, error) {
	e := &Episode{}
	err := s.db.QueryRow("SELECT id, user_id, title, description, audio_path, image_path, published_at, created_at FROM episodes WHERE id = ?", id).
		Scan(&e.ID, &e.UserID, &e.Title, &e.Description, &e.AudioPath, &e.ImagePath, &e.PublishedAt, &e.CreatedAt)
	if err != nil {
		return nil, err
	}
	return e, nil
}

func (s *Store) CreateEpisode(userID int64, title, description, audioPath, imagePath string, publishedAt time.Time) (int64, error) {
	res, err := s.db.Exec("INSERT INTO episodes (user_id, title, description, audio_path, image_path, published_at) VALUES (?, ?, ?, ?, ?, ?)",
		userID, title, description, audioPath, imagePath, publishedAt)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

func (s *Store) UpdateEpisode(id int64, title, description, audioPath, imagePath string, publishedAt time.Time) error {
	_, err := s.db.Exec("UPDATE episodes SET title=?, description=?, audio_path=?, image_path=?, published_at=? WHERE id=?",
		title, description, audioPath, imagePath, publishedAt, id)
	return err
}

func (s *Store) DeleteEpisode(id int64) error {
	_, err := s.db.Exec("DELETE FROM episodes WHERE id = ?", id)
	return err
}
