package models

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

type NullString struct {
	sql.NullString
}

func (ns NullString) MarshalJSON() ([]byte, error) {
	if ns.Valid {
		return json.Marshal(ns.String)
	}
	return json.Marshal("")
}

func (ns *NullString) UnmarshalJSON(data []byte) error {
	if string(data) == "null" {
		ns.Valid = false
		ns.String = ""
		return nil
	}
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	ns.String = s
	ns.Valid = true
	return nil
}

type Machine struct {
	ID           int64      `json:"id"`
	Hostname     string     `json:"hostname"`
	IP           string     `json:"ip"`
	MAC          NullString `json:"mac"`
	OsType       string     `json:"os_type"`
	OsVersion    NullString `json:"os_version"`
	Notes        NullString `json:"notes"`
	SSHPort      int        `json:"ssh_port"`
	SSHUsername  NullString `json:"ssh_username"`
	SSHPassword  NullString `json:"ssh_password"`
	IsOnline     bool       `json:"is_online"`
	LastPingAt   *time.Time `json:"last_ping_at"`
	CPUInfo      NullString `json:"cpu_info"`
	MemoryInfo   NullString `json:"memory_info"`
	DiskInfo     NullString `json:"disk_info"`
	Uptime       NullString `json:"uptime"`
	ListenPorts  NullString `json:"listen_ports"`
	SSHSyncedAt  *time.Time `json:"ssh_synced_at"`
	CreatedAt    time.Time  `json:"created_at"`
	UpdatedAt    time.Time  `json:"updated_at"`
	ServiceCount          int        `json:"service_count"`
	OfflineCount          int        `json:"offline_count"`
	TotalOfflineSeconds   int        `json:"total_offline_seconds"`
	LastOfflineAt         *time.Time `json:"last_offline_at"`
	LastOfflineReason     NullString `json:"last_offline_reason"`
}

type OfflineLog struct {
	ID              int64      `json:"id"`
	MachineID       int64      `json:"machine_id"`
	Reason          string     `json:"reason"`
	StartedAt       time.Time  `json:"started_at"`
	EndedAt         *time.Time `json:"ended_at"`
	DurationSeconds *int       `json:"duration_seconds"`
}

type Service struct {
	ID             int64  `json:"id"`
	MachineID      int64  `json:"machine_id"`
	Name           string `json:"name"`
	Port           int    `json:"port"`
	Protocol       string `json:"protocol"`
	Notes          string `json:"notes"`
	TargetMachineID *int64 `json:"target_machine_id"`
	TargetNotes    string `json:"target_notes"`
}

type Relationship struct {
	ID              int64  `json:"id"`
	SourceMachineID int64  `json:"source_machine_id"`
	TargetMachineID int64  `json:"target_machine_id"`
	RelationType    string `json:"relation_type"`
	SourcePort      *int   `json:"source_port"`
	TargetPort      *int   `json:"target_port"`
	Notes           string `json:"notes"`
}

type OperationLog struct {
	ID         int64     `json:"id"`
	Action     string    `json:"action"`
	EntityType string    `json:"entity_type"`
	EntityID   *int64    `json:"entity_id"`
	EntityName string    `json:"entity_name"`
	OldValue   string    `json:"old_value"`
	NewValue   string    `json:"new_value"`
	SourceIP   string    `json:"source_ip"`
	Username   string    `json:"username"`
	CreatedAt  time.Time `json:"created_at"`
}

type LoginRequest struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

type SSHInfoRequest struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password"`
}

type SSHInfoResult struct {
	Hostname      string   `json:"hostname"`
	OsVersion     string   `json:"os_version"`
	CPU           string   `json:"cpu"`
	Memory        string   `json:"memory"`
	Disk          string   `json:"disk"`
	Uptime        string   `json:"uptime"`
	ListenPorts   []int    `json:"listen_ports"`
	RawCPUInfo    string   `json:"raw_cpu_info"`
	RawMemoryInfo string   `json:"raw_memory_info"`
	RawDiskInfo   string   `json:"raw_disk_info"`
}
