package db

import (
	"encoding/json"
	"time"

	"skraak/utils"
)

// DatasetType represents the dataset_type enum from the schema
type DatasetType string

// Dataset type enum constants
const (
	DatasetTypeStructured   DatasetType = "structured"
	DatasetTypeUnstructured DatasetType = "unstructured"
	DatasetTypeTest         DatasetType = "test"
	DatasetTypeTrain        DatasetType = "train"
)

// Dataset represents a row from the dataset table
type Dataset struct {
	ID           string      `json:"id"`
	Name         string      `json:"name"`
	Description  *string     `json:"description"` // Pointer for nullable field
	CreatedAt    time.Time   `json:"created_at"`
	LastModified time.Time   `json:"last_modified"`
	Active       bool        `json:"active"`
	Type         DatasetType `json:"type"`
}

// MarshalJSON implements custom JSON marshaling for Dataset
// Formats timestamps as RFC3339
func (d Dataset) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		ID           string      `json:"id"`
		Name         string      `json:"name"`
		Description  *string     `json:"description"`
		CreatedAt    string      `json:"created_at"`
		LastModified string      `json:"last_modified"`
		Active       bool        `json:"active"`
		Type         DatasetType `json:"type"`
	}{
		ID:           d.ID,
		Name:         d.Name,
		Description:  d.Description,
		CreatedAt:    d.CreatedAt.Format(time.RFC3339),
		LastModified: d.LastModified.Format(time.RFC3339),
		Active:       d.Active,
		Type:         d.Type,
	})
}

// Location represents a row from the location table
type Location struct {
	ID           string    `json:"id"`
	DatasetID    string    `json:"dataset_id"`
	Name         string    `json:"name"`
	Latitude     float64   `json:"latitude"`
	Longitude    float64   `json:"longitude"`
	Description  *string   `json:"description"` // nullable
	CreatedAt    time.Time `json:"created_at"`
	LastModified time.Time `json:"last_modified"`
	Active       bool      `json:"active"`
	TimezoneID   string    `json:"timezone_id"`
}

// MarshalJSON implements custom JSON marshaling for Location
// Formats timestamps as RFC3339
func (l Location) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		ID           string  `json:"id"`
		DatasetID    string  `json:"dataset_id"`
		Name         string  `json:"name"`
		Latitude     float64 `json:"latitude"`
		Longitude    float64 `json:"longitude"`
		Description  *string `json:"description"`
		CreatedAt    string  `json:"created_at"`
		LastModified string  `json:"last_modified"`
		Active       bool    `json:"active"`
		TimezoneID   string  `json:"timezone_id"`
	}{
		ID:           l.ID,
		DatasetID:    l.DatasetID,
		Name:         l.Name,
		Latitude:     l.Latitude,
		Longitude:    l.Longitude,
		Description:  l.Description,
		CreatedAt:    l.CreatedAt.Format(time.RFC3339),
		LastModified: l.LastModified.Format(time.RFC3339),
		Active:       l.Active,
		TimezoneID:   l.TimezoneID,
	})
}

// Cluster represents a row from the cluster table
type Cluster struct {
	ID                       string    `json:"id"`
	DatasetID                string    `json:"dataset_id"`
	LocationID               string    `json:"location_id"`
	Name                     string    `json:"name"`
	Description              *string   `json:"description"` // nullable
	CreatedAt                time.Time `json:"created_at"`
	LastModified             time.Time `json:"last_modified"`
	Active                   bool      `json:"active"`
	CyclicRecordingPatternID *string   `json:"cyclic_recording_pattern_id"` // nullable
	SampleRate               int       `json:"sample_rate"`
}

// MarshalJSON implements custom JSON marshaling for Cluster
// Formats timestamps as RFC3339
func (c Cluster) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		ID                       string  `json:"id"`
		DatasetID                string  `json:"dataset_id"`
		LocationID               string  `json:"location_id"`
		Name                     string  `json:"name"`
		Description              *string `json:"description"`
		CreatedAt                string  `json:"created_at"`
		LastModified             string  `json:"last_modified"`
		Active                   bool    `json:"active"`
		CyclicRecordingPatternID *string `json:"cyclic_recording_pattern_id"`
		SampleRate               int     `json:"sample_rate"`
	}{
		ID:                       c.ID,
		DatasetID:                c.DatasetID,
		LocationID:               c.LocationID,
		Name:                     c.Name,
		Description:              c.Description,
		CreatedAt:                c.CreatedAt.Format(time.RFC3339),
		LastModified:             c.LastModified.Format(time.RFC3339),
		Active:                   c.Active,
		CyclicRecordingPatternID: c.CyclicRecordingPatternID,
		SampleRate:               c.SampleRate,
	})
}

// File represents a row from the file table
type File struct {
	ID              string    `json:"id"`
	FileName        string    `json:"file_name"`
	Path            *string   `json:"path"` // nullable
	XXH64Hash       string    `json:"xxh64_hash"`
	LocationID      string    `json:"location_id"`
	TimestampLocal  time.Time `json:"timestamp_local"`
	ClusterID       *string   `json:"cluster_id"` // nullable
	Duration        float64   `json:"duration"`
	SampleRate      int       `json:"sample_rate"`
	Description     *string   `json:"description"`       // nullable
	MaybeSolarNight *bool     `json:"maybe_solar_night"` // nullable
	MaybeCivilNight *bool     `json:"maybe_civil_night"` // nullable
	MoonPhase       *float64  `json:"moon_phase"`        // nullable
	CreatedAt       time.Time `json:"created_at"`
	LastModified    time.Time `json:"last_modified"`
	Active          bool      `json:"active"`
}

// CyclicRecordingPattern represents a row from the cyclic_recording_pattern table
type CyclicRecordingPattern struct {
	ID           string    `json:"id"`
	RecordS      int       `json:"record_s"`
	SleepS       int       `json:"sleep_s"`
	CreatedAt    time.Time `json:"created_at"`
	LastModified time.Time `json:"last_modified"`
	Active       bool      `json:"active"`
}

// MarshalJSON implements custom JSON marshaling for CyclicRecordingPattern
// Formats timestamps as RFC3339
func (p CyclicRecordingPattern) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		ID           string `json:"id"`
		RecordS      int    `json:"record_s"`
		SleepS       int    `json:"sleep_s"`
		CreatedAt    string `json:"created_at"`
		LastModified string `json:"last_modified"`
		Active       bool   `json:"active"`
	}{
		ID:           p.ID,
		RecordS:      p.RecordS,
		SleepS:       p.SleepS,
		CreatedAt:    p.CreatedAt.Format(time.RFC3339),
		LastModified: p.LastModified.Format(time.RFC3339),
		Active:       p.Active,
	})
}

// GainLevel is re-exported from utils for backward compatibility.
type GainLevel = utils.GainLevel

// Gain level constants re-exported from utils.
const (
	GainLow        = utils.GainLow
	GainLowMedium  = utils.GainLowMedium
	GainMedium     = utils.GainMedium
	GainMediumHigh = utils.GainMediumHigh
	GainHigh       = utils.GainHigh
)

// MothMetadata represents a row from the moth_metadata table
type MothMetadata struct {
	FileID       string     `json:"file_id"`
	Timestamp    time.Time  `json:"timestamp"`
	RecorderID   *string    `json:"recorder_id"` // nullable
	Gain         *GainLevel `json:"gain"`        // nullable
	BatteryV     *float64   `json:"battery_v"`   // nullable
	TempC        *float64   `json:"temp_c"`      // nullable
	CreatedAt    time.Time  `json:"created_at"`
	LastModified time.Time  `json:"last_modified"`
	Active       bool       `json:"active"`
}

// FileDataset represents a row from the file_dataset junction table
type FileDataset struct {
	FileID       string    `json:"file_id"`
	DatasetID    string    `json:"dataset_id"`
	CreatedAt    time.Time `json:"created_at"`
	LastModified time.Time `json:"last_modified"`
}