package storage

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

type PersonRecord struct {
    ID         int      `json:"id"`
    Name       string   `json:"name"`
    PhotoCount int      `json:"photo_count"`
    Photos     []string `json:"photos,omitempty"`
    PhotoIDs   []int    `json:"photo_ids,omitempty"`
    CreatedAt  string   `json:"created_at"`
}

type FaceGalleryRepo struct {
    dbPath string
}

func NewFaceGalleryRepo(dbPath string) *FaceGalleryRepo {
    return &FaceGalleryRepo{dbPath: dbPath}
}

func (r *FaceGalleryRepo) open() (*sql.DB, error) {
    db, err := sql.Open("sqlite", r.dbPath)
    if err != nil {
        return nil, fmt.Errorf("open app db: %w", err)
    }
    _, err = db.Exec(`
CREATE TABLE IF NOT EXISTS face_persons (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT '',
  updated_at TEXT NOT NULL DEFAULT ''
);
CREATE TABLE IF NOT EXISTS face_photos (
  id INTEGER PRIMARY KEY,
  person_id INTEGER NOT NULL,
  photo_path TEXT NOT NULL DEFAULT '',
  created_at TEXT NOT NULL DEFAULT ''
);
`)
    if err != nil {
        db.Close()
        return nil, fmt.Errorf("ensure face tables: %w", err)
    }
    return db, nil
}

func (r *FaceGalleryRepo) ListPersons() ([]PersonRecord, error) {
    db, err := r.open()
    if err != nil {
        return nil, err
    }
    defer db.Close()

    rows, err := db.Query(`SELECT id, name, created_at FROM face_persons ORDER BY name`)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var out []PersonRecord
    for rows.Next() {
        var p PersonRecord
        if err := rows.Scan(&p.ID, &p.Name, &p.CreatedAt); err != nil {
            continue
        }
        out = append(out, p)
    }
    // Load photos for each person
    for i := range out {
        photoRows, err := db.Query(`SELECT photo_path, id FROM face_photos WHERE person_id = ? ORDER BY id`, out[i].ID)
        if err != nil {
            continue
        }
        for photoRows.Next() {
            var path string
            var pid int
            if photoRows.Scan(&path, &pid) == nil {
                out[i].Photos = append(out[i].Photos, path)
                out[i].PhotoIDs = append(out[i].PhotoIDs, pid)
            }
        }
        photoRows.Close()
        out[i].PhotoCount = len(out[i].Photos)
    }
    if out == nil {
        out = make([]PersonRecord, 0)
    }
    return out, rows.Err()
}

func (r *FaceGalleryRepo) AddPerson(name string) error {
    db, err := r.open()
    if err != nil {
        return err
    }
    defer db.Close()
    now := time.Now().Format(time.RFC3339)
    _, err = db.Exec(`INSERT INTO face_persons(name, created_at, updated_at) VALUES(?, ?, ?)`, name, now, now)
    return err
}

func (r *FaceGalleryRepo) AddPhoto(personID int, photoPath string) error {
    db, err := r.open()
    if err != nil {
        return err
    }
    defer db.Close()
    // Skip if already exists
    var existing int
    if db.QueryRow(`SELECT COUNT(*) FROM face_photos WHERE person_id = ? AND photo_path = ?`, personID, photoPath).Scan(&existing) == nil && existing > 0 {
        return nil
    }
    now := time.Now().Format(time.RFC3339)
    _, err = db.Exec(`INSERT INTO face_photos(person_id, photo_path, created_at) VALUES(?, ?, ?)`, personID, photoPath, now)
    return err
}

func (r *FaceGalleryRepo) FindOrCreatePerson(name string) (int, error) {
    db, err := r.open()
    if err != nil {
        return 0, err
    }
    defer db.Close()
    var id int
    err = db.QueryRow(`SELECT id FROM face_persons WHERE name = ?`, name).Scan(&id)
    if err == nil {
        return id, nil
    }
    now := time.Now().Format(time.RFC3339)
    res, err := db.Exec(`INSERT INTO face_persons(name, created_at, updated_at) VALUES(?, ?, ?)`, name, now, now)
    if err != nil {
        return 0, err
    }
    lid, _ := res.LastInsertId()
    return int(lid), nil
}

func (r *FaceGalleryRepo) DeletePerson(id int) error {
    db, err := r.open()
    if err != nil {
        return err
    }
    defer db.Close()
    _, err = db.Exec(`DELETE FROM face_photos WHERE person_id = ?`, id)
    if err != nil {
        return err
    }
    _, err = db.Exec(`DELETE FROM face_persons WHERE id = ?`, id)
    return err
}

func (r *FaceGalleryRepo) RenamePerson(id int, name string) error {
    db, err := r.open()
    if err != nil {
        return err
    }
    defer db.Close()
    now := time.Now().Format(time.RFC3339)
    _, err = db.Exec(`UPDATE face_persons SET name = ?, updated_at = ? WHERE id = ?`, name, now, id)
    return err
}

func (r *FaceGalleryRepo) DeletePhoto(photoID int) error {
    db, err := r.open()
    if err != nil { return err }
    defer db.Close()
    // Get path before deleting
    var path string
    db.QueryRow(`SELECT photo_path FROM face_photos WHERE id = ?`, photoID).Scan(&path)
    _, err = db.Exec(`DELETE FROM face_photos WHERE id = ?`, photoID)
    if err != nil { return err }
    // Remove file from disk
    if path != "" { os.Remove(filepath.Join("dataset", path)) }
    return nil
}
