package db

import (
	"encoding/json"
	"time"
)

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

// Dataset type enum constants
const (
	DatasetTypeOrganise DatasetType = "organise"
	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"`
}

// MarshalJSON implements custom JSON marshaling for File
// Formats timestamps as RFC3339
func (f File) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		ID              string   `json:"id"`
		FileName        string   `json:"file_name"`
		Path            *string  `json:"path"`
		XXH64Hash       string   `json:"xxh64_hash"`
		LocationID      string   `json:"location_id"`
		TimestampLocal  string   `json:"timestamp_local"`
		ClusterID       *string  `json:"cluster_id"`
		Duration        float64  `json:"duration"`
		SampleRate      int      `json:"sample_rate"`
		Description     *string  `json:"description"`
		MaybeSolarNight *bool    `json:"maybe_solar_night"`
		MaybeCivilNight *bool    `json:"maybe_civil_night"`
		MoonPhase       *float64 `json:"moon_phase"`
		CreatedAt       string   `json:"created_at"`
		LastModified    string   `json:"last_modified"`
		Active          bool     `json:"active"`
	}{
		ID:              f.ID,
		FileName:        f.FileName,
		Path:            f.Path,
		XXH64Hash:       f.XXH64Hash,
		LocationID:      f.LocationID,
		TimestampLocal:  f.TimestampLocal.Format(time.RFC3339),
		ClusterID:       f.ClusterID,
		Duration:        f.Duration,
		SampleRate:      f.SampleRate,
		Description:     f.Description,
		MaybeSolarNight: f.MaybeSolarNight,
		MaybeCivilNight: f.MaybeCivilNight,
		MoonPhase:       f.MoonPhase,
		CreatedAt:       f.CreatedAt.Format(time.RFC3339),
		LastModified:    f.LastModified.Format(time.RFC3339),
		Active:          f.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 represents the gain_level enum for AudioMoth recordings
type GainLevel string

// AudioMoth gain level enum constants
const (
	GainLow        GainLevel = "low"
	GainLowMedium  GainLevel = "low-medium"
	GainMedium     GainLevel = "medium"
	GainMediumHigh GainLevel = "medium-high"
	GainHigh       GainLevel = "high"
)

// 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"`
}

// MarshalJSON implements custom JSON marshaling for MothMetadata
// Formats timestamps as RFC3339
func (m MothMetadata) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		FileID       string     `json:"file_id"`
		Timestamp    string     `json:"timestamp"`
		RecorderID   *string    `json:"recorder_id"`
		Gain         *GainLevel `json:"gain"`
		BatteryV     *float64   `json:"battery_v"`
		TempC        *float64   `json:"temp_c"`
		CreatedAt    string     `json:"created_at"`
		LastModified string     `json:"last_modified"`
		Active       bool       `json:"active"`
	}{
		FileID:       m.FileID,
		Timestamp:    m.Timestamp.Format(time.RFC3339),
		RecorderID:   m.RecorderID,
		Gain:         m.Gain,
		BatteryV:     m.BatteryV,
		TempC:        m.TempC,
		CreatedAt:    m.CreatedAt.Format(time.RFC3339),
		LastModified: m.LastModified.Format(time.RFC3339),
		Active:       m.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"`
}

// MarshalJSON implements custom JSON marshaling for FileDataset
// Formats timestamps as RFC3339
func (fd FileDataset) MarshalJSON() ([]byte, error) {
	return json.Marshal(&struct {
		FileID       string `json:"file_id"`
		DatasetID    string `json:"dataset_id"`
		CreatedAt    string `json:"created_at"`
		LastModified string `json:"last_modified"`
	}{
		FileID:       fd.FileID,
		DatasetID:    fd.DatasetID,
		CreatedAt:    fd.CreatedAt.Format(time.RFC3339),
		LastModified: fd.LastModified.Format(time.RFC3339),
	})
}