package storage

import (
    "database/sql"
    "encoding/json"
    "time"

	"safesight-control/internal/models"
)

type DevicesRepo struct {
    db *sql.DB
}

func NewDevicesRepo(db *sql.DB) *DevicesRepo {
    return &DevicesRepo{db: db}
}

func (r *DevicesRepo) Upsert(dev *models.Device) error {
    if r == nil || r.db == nil || dev == nil {
        return nil
    }
    graphs, err := json.Marshal(dev.Graphs)
    if err != nil {
        return err
    }
    if string(graphs) == "null" {
        graphs = []byte(`{}`)
    }
    _, err = r.db.Exec(`
INSERT INTO devices(device_id, hostname, ip, agent_port, media_port, alias, device_name, version, git_sha, build_id, last_seen_ms, online, graphs_json, updated_at)
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(device_id) DO UPDATE SET
  hostname=excluded.hostname,
  ip=excluded.ip,
  agent_port=excluded.agent_port,
  media_port=excluded.media_port,
  alias=excluded.alias,
  device_name=excluded.device_name,
  version=excluded.version,
  git_sha=excluded.git_sha,
  build_id=excluded.build_id,
  last_seen_ms=excluded.last_seen_ms,
  online=excluded.online,
  graphs_json=excluded.graphs_json,
  updated_at=excluded.updated_at
`, dev.DeviceID, dev.Hostname, dev.IP, dev.AgentPort, dev.MediaPort, dev.DeviceAlias, dev.DeviceName, dev.Version, dev.GitSha, dev.BuildID, dev.LastSeenMs, boolToInt(dev.Online), string(graphs), time.Now().Format(time.RFC3339))
    return err
}

func (r *DevicesRepo) List() ([]*models.Device, error) {
    if r == nil || r.db == nil {
        return nil, nil
    }
    rows, err := r.db.Query(`
SELECT device_id, hostname, ip, agent_port, media_port, alias, device_name, version, git_sha, build_id, last_seen_ms, online, graphs_json
FROM devices
ORDER BY updated_at DESC, device_id ASC
`)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var out []*models.Device
    for rows.Next() {
        var (
            dev                            models.Device
            onlineInt                      int
            graphsJSON                     string
        )
        if err := rows.Scan(&dev.DeviceID, &dev.Hostname, &dev.IP, &dev.AgentPort, &dev.MediaPort, &dev.DeviceAlias, &dev.DeviceName, &dev.Version, &dev.GitSha, &dev.BuildID, &dev.LastSeenMs, &onlineInt, &graphsJSON); err != nil {
            return nil, err
        }
        dev.Online = onlineInt == 1
        if graphsJSON != "" && graphsJSON != "{}" {
            var graphs any
            if err := json.Unmarshal([]byte(graphsJSON), &graphs); err != nil {
                return nil, err
            }
            dev.Graphs = graphs
        }
        out = append(out, &dev)
    }
    return out, rows.Err()
}

func boolToInt(v bool) int {
    if v {
        return 1
    }
    return 0
}
