package db

import (
	"database/sql"
	"fmt"
	"os"
	"path/filepath"
	"time"

	_ "modernc.org/sqlite"
)

type Alarm struct {
	ID            int
	Name          string
	Description   string
	Time          string // HH:MM format for simple alarms
	Trigger       string // Cron expression or "once"
	SoundPath     string
	Enabled       bool
	CreatedAt     time.Time
	UpdatedAt     time.Time
	LastTriggered *time.Time
	SnoozeCount   int
}

type AlarmHistory struct {
	ID          int
	AlarmID     int
	TriggeredAt time.Time
	DismissedAt *time.Time
	SnoozedCount int
}

type Store struct {
	db *sql.DB
}

func Open() (*Store, error) {
	home, err := os.UserHomeDir()
	if err != nil {
		return nil, fmt.Errorf("get home dir: %w", err)
	}

	dir := filepath.Join(home, ".config", "woke")
	if err := os.MkdirAll(dir, 0755); err != nil {
		return nil, fmt.Errorf("create config dir: %w", err)
	}

	dbPath := filepath.Join(dir, "woke.db")
	db, err := sql.Open("sqlite", dbPath)
	if err != nil {
		return nil, fmt.Errorf("open database: %w", err)
	}

	store := &Store{db: db}
	if err := store.migrate(); err != nil {
		db.Close()
		return nil, fmt.Errorf("migrate: %w", err)
	}

	return store, nil
}

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

func (s *Store) migrate() error {
	_, err := s.db.Exec(`
		CREATE TABLE IF NOT EXISTS alarms (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			name TEXT NOT NULL,
			description TEXT DEFAULT '',
			time TEXT DEFAULT '',
			trigger TEXT NOT NULL,
			sound_path TEXT NOT NULL DEFAULT 'default',
			enabled BOOLEAN DEFAULT 1,
			created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
			last_triggered TIMESTAMP,
			snooze_count INTEGER DEFAULT 0
		);

		CREATE TABLE IF NOT EXISTS alarm_history (
			id INTEGER PRIMARY KEY AUTOINCREMENT,
			alarm_id INTEGER,
			triggered_at TIMESTAMP,
			dismissed_at TIMESTAMP,
			snoozed_count INTEGER DEFAULT 0,
			FOREIGN KEY (alarm_id) REFERENCES alarms(id)
		);

		CREATE TABLE IF NOT EXISTS settings (
			key TEXT PRIMARY KEY,
			value TEXT
		);
	`)
	return err
}

func (s *Store) ListAlarms() ([]Alarm, error) {
	rows, err := s.db.Query(`
		SELECT id, name, description, time, trigger, sound_path, enabled,
		       created_at, updated_at, last_triggered, snooze_count
		FROM alarms ORDER BY time ASC, name ASC
	`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var alarms []Alarm
	for rows.Next() {
		var a Alarm
		var lastTriggered sql.NullTime
		err := rows.Scan(&a.ID, &a.Name, &a.Description, &a.Time, &a.Trigger,
			&a.SoundPath, &a.Enabled, &a.CreatedAt, &a.UpdatedAt,
			&lastTriggered, &a.SnoozeCount)
		if err != nil {
			return nil, err
		}
		if lastTriggered.Valid {
			a.LastTriggered = &lastTriggered.Time
		}
		alarms = append(alarms, a)
	}
	return alarms, rows.Err()
}

func (s *Store) GetAlarm(id int) (Alarm, error) {
	var a Alarm
	var lastTriggered sql.NullTime
	err := s.db.QueryRow(`
		SELECT id, name, description, time, trigger, sound_path, enabled,
		       created_at, updated_at, last_triggered, snooze_count
		FROM alarms WHERE id = ?
	`, id).Scan(&a.ID, &a.Name, &a.Description, &a.Time, &a.Trigger,
		&a.SoundPath, &a.Enabled, &a.CreatedAt, &a.UpdatedAt,
		&lastTriggered, &a.SnoozeCount)
	if lastTriggered.Valid {
		a.LastTriggered = &lastTriggered.Time
	}
	return a, err
}

func (s *Store) CreateAlarm(a Alarm) (int, error) {
	result, err := s.db.Exec(`
		INSERT INTO alarms (name, description, time, trigger, sound_path, enabled)
		VALUES (?, ?, ?, ?, ?, ?)
	`, a.Name, a.Description, a.Time, a.Trigger, a.SoundPath, a.Enabled)
	if err != nil {
		return 0, err
	}
	id, err := result.LastInsertId()
	return int(id), err
}

func (s *Store) UpdateAlarm(a Alarm) error {
	_, err := s.db.Exec(`
		UPDATE alarms SET name=?, description=?, time=?, trigger=?, sound_path=?,
		       enabled=?, updated_at=CURRENT_TIMESTAMP
		WHERE id=?
	`, a.Name, a.Description, a.Time, a.Trigger, a.SoundPath, a.Enabled, a.ID)
	return err
}

func (s *Store) DeleteAlarm(id int) error {
	_, err := s.db.Exec(`DELETE FROM alarms WHERE id=?`, id)
	return err
}

func (s *Store) ToggleAlarm(id int) error {
	_, err := s.db.Exec(`
		UPDATE alarms SET enabled = NOT enabled, updated_at = CURRENT_TIMESTAMP WHERE id = ?
	`, id)
	return err
}

func (s *Store) MarkTriggered(id int) error {
	now := time.Now()
	_, err := s.db.Exec(`
		UPDATE alarms SET last_triggered = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
	`, now, id)
	if err != nil {
		return err
	}
	_, err = s.db.Exec(`
		INSERT INTO alarm_history (alarm_id, triggered_at) VALUES (?, ?)
	`, id, now)
	return err
}

func (s *Store) GetSetting(key, defaultVal string) string {
	var val string
	err := s.db.QueryRow(`SELECT value FROM settings WHERE key = ?`, key).Scan(&val)
	if err != nil {
		return defaultVal
	}
	return val
}

func (s *Store) SetSetting(key, value string) error {
	_, err := s.db.Exec(`
		INSERT INTO settings (key, value) VALUES (?, ?)
		ON CONFLICT(key) DO UPDATE SET value = excluded.value
	`, key, value)
	return err
}
