package database

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

func InitDB(db *sql.DB) {
	schema := `
    CREATE TABLE IF NOT EXISTS currencies (
        id   INTEGER PRIMARY KEY AUTOINCREMENT,
        code TEXT    NOT NULL UNIQUE,
        name TEXT    NOT NULL
    );

    CREATE TABLE IF NOT EXISTS trades (
        id          INTEGER PRIMARY KEY AUTOINCREMENT,
        company_id  INTEGER NOT NULL,
        currency_id INTEGER NOT NULL,
        shares      INTEGER NOT NULL,
        product     INTEGER NOT NULL CHECK(product IN (0, 1, 2, 3)),
        type        INTEGER NOT NULL CHECK(type IN (0, 1)),
        price       REAL    NOT NULL,
        traded_at   DATETIME NOT NULL
    );

    CREATE TABLE IF NOT EXISTS position (
        id          INTEGER PRIMARY KEY AUTOINCREMENT,
        company_id  INTEGER NOT NULL,
        currency_id INTEGER NOT NULL,
        shares      INTEGER NOT NULL,
        weight      REAL NOT NULL,
        cost_basis  REAL NOT NULL
    );

    CREATE TABLE IF NOT EXISTS companies (
        id                 INTEGER PRIMARY KEY AUTOINCREMENT,
        name               TEXT    NOT NULL UNIQUE,
        shares_outstanding INTEGER NOT NULL,
        price              REAL    NOT NULL,
        currency_id        INTEGER NOT NULL,
        FOREIGN KEY (currency_id) REFERENCES currencies(id)
    );

    CREATE TABLE IF NOT EXISTS periods (
        id         INTEGER PRIMARY KEY AUTOINCREMENT,
        type       TEXT    NOT NULL CHECK(type IN ('Q', 'H', 'Y')),
        year       INTEGER NOT NULL,
        idx        INTEGER NOT NULL,
        start_date TEXT    NOT NULL,
        end_date   TEXT    NOT NULL,
        UNIQUE(type, year, idx)
    );

    CREATE TABLE IF NOT EXISTS category (
        id         INTEGER PRIMARY KEY AUTOINCREMENT,
        company_id INTEGER NOT NULL,
        parent_id  INTEGER,
        name       TEXT    NOT NULL,
        FOREIGN KEY (company_id) REFERENCES companies(id),
        FOREIGN KEY (parent_id)  REFERENCES category(id),
        UNIQUE(company_id, name)
    );

    CREATE TABLE IF NOT EXISTS revenue_entries (
        id          INTEGER PRIMARY KEY AUTOINCREMENT,
        company_id  INTEGER NOT NULL,
        currency_id INTEGER NOT NULL,
        category_id INTEGER NOT NULL,
        period_id   INTEGER NOT NULL,
        value       REAL    NOT NULL,
        FOREIGN KEY (company_id)  REFERENCES companies(id),
        FOREIGN KEY (currency_id) REFERENCES currencies(id),
        FOREIGN KEY (category_id) REFERENCES category(id),
        FOREIGN KEY (period_id)   REFERENCES periods(id),
        UNIQUE(company_id, category_id, period_id)
    );`

	if _, err := db.Exec(schema); err != nil {
		log.Fatal("Failed to create tables:", err)
	}
	fmt.Println("Tables ready")
}

func MigrateAddUniqueToRevenueEntries(db *sql.DB) error {
	steps := []string{
		// 1. copy existing data into a temp table with the new constraint
		`CREATE TABLE IF NOT EXISTS revenue_entries_new (
			id          INTEGER PRIMARY KEY AUTOINCREMENT,
			company_id  INTEGER NOT NULL,
			currency_id INTEGER NOT NULL,
			category_id INTEGER NOT NULL,
			period_id   INTEGER NOT NULL,
			value       REAL    NOT NULL,
			FOREIGN KEY (company_id)  REFERENCES companies(id),
			FOREIGN KEY (currency_id) REFERENCES currencies(id),
			FOREIGN KEY (category_id) REFERENCES category(id),
			FOREIGN KEY (period_id)   REFERENCES periods(id),
			UNIQUE(company_id, category_id, period_id)
		)`,
		// 2. copy data over
		`INSERT OR IGNORE INTO revenue_entries_new
			SELECT id, company_id, currency_id, category_id, period_id, value
			FROM revenue_entries`,
		// 3. drop old table
		`DROP TABLE revenue_entries`,
		// 4. rename new table
		`ALTER TABLE revenue_entries_new RENAME TO revenue_entries`,
	}

	for _, step := range steps {
		if _, err := db.Exec(step); err != nil {
			return fmt.Errorf("migration failed: %w", err)
		}
	}
	return nil
}
