package handlers

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

	"github.com/gin-gonic/gin"
	"lan-manager/server/db"
	"lan-manager/server/middleware"
	"lan-manager/server/models"
)

type ExportHandler struct{}

func NewExportHandler() *ExportHandler {
	return &ExportHandler{}
}

func (h *ExportHandler) Export(c *gin.Context) {
	data := map[string]interface{}{}

	machines := []models.Machine{}
	if rows, err := db.DB.Query(`SELECT id, hostname, ip, mac, os_type, os_version, notes, ssh_port, ssh_username, ssh_password, is_online, last_ping_at, cpu_info, memory_info, disk_info, uptime, listen_ports, ssh_synced_at, created_at, updated_at FROM machines`); err == nil {
		defer rows.Close()
		for rows.Next() {
			var m models.Machine
			var lp, ss *time.Time
			if err := rows.Scan(&m.ID, &m.Hostname, &m.IP, &m.MAC, &m.OsType, &m.OsVersion, &m.Notes, &m.SSHPort, &m.SSHUsername, &m.SSHPassword, &m.IsOnline, &lp, &m.CPUInfo, &m.MemoryInfo, &m.DiskInfo, &m.Uptime, &m.ListenPorts, &ss, &m.CreatedAt, &m.UpdatedAt); err == nil {
				m.LastPingAt = lp
				m.SSHSyncedAt = ss
				machines = append(machines, m)
			}
		}
	}
	data["machines"] = machines

	services := []models.Service{}
	if rows, err := db.DB.Query(`SELECT id, machine_id, name, port, protocol, notes, target_machine_id, target_notes FROM services`); err == nil {
		defer rows.Close()
		for rows.Next() {
			var s models.Service
			var tm sql.NullInt64
			if err := rows.Scan(&s.ID, &s.MachineID, &s.Name, &s.Port, &s.Protocol, &s.Notes, &tm, &s.TargetNotes); err == nil {
				if tm.Valid {
					tmid := tm.Int64
					s.TargetMachineID = &tmid
				}
				services = append(services, s)
			}
		}
	}
	data["services"] = services

	relationships := []models.Relationship{}
	if rows, err := db.DB.Query(`SELECT id, source_machine_id, target_machine_id, relation_type, source_port, target_port, notes FROM relationships`); err == nil {
		defer rows.Close()
		for rows.Next() {
			var r models.Relationship
			if err := rows.Scan(&r.ID, &r.SourceMachineID, &r.TargetMachineID, &r.RelationType, &r.SourcePort, &r.TargetPort, &r.Notes); err == nil {
				relationships = append(relationships, r)
			}
		}
	}
	data["relationships"] = relationships

	b, _ := json.MarshalIndent(data, "", "  ")
	filename := "lan-manager-backup-" + time.Now().Format("20060102") + ".json"
	c.Header("Content-Disposition", "attachment; filename="+filename)
	c.Data(http.StatusOK, "application/json", b)
}

func (h *ExportHandler) Import(c *gin.Context) {
	file, _, err := c.Request.FormFile("file")
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	defer file.Close()

	var data map[string]json.RawMessage
	if err := json.NewDecoder(file).Decode(&data); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	mode := c.DefaultPostForm("mode", "append")
	if mode == "overwrite" {
		_, _ = db.DB.Exec(`DELETE FROM relationships`)
		_, _ = db.DB.Exec(`DELETE FROM services`)
		_, _ = db.DB.Exec(`DELETE FROM machines`)
	}

	if raw, ok := data["machines"]; ok {
		var list []models.Machine
		if err := json.Unmarshal(raw, &list); err == nil {
			for _, m := range list {
				_, _ = db.DB.Exec(`INSERT OR IGNORE INTO machines (id, hostname, ip, mac, os_type, os_version, notes, ssh_port, ssh_username, ssh_password, is_online, cpu_info, memory_info, disk_info, uptime, listen_ports) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
					m.ID, m.Hostname, m.IP, m.MAC, m.OsType, m.OsVersion, m.Notes, m.SSHPort, m.SSHUsername, m.SSHPassword, 0, m.CPUInfo, m.MemoryInfo, m.DiskInfo, m.Uptime, m.ListenPorts)
			}
		}
	}

	if raw, ok := data["services"]; ok {
		var list []models.Service
		if err := json.Unmarshal(raw, &list); err == nil {
			for _, s := range list {
				_, _ = db.DB.Exec(`INSERT OR IGNORE INTO services (id, machine_id, name, port, protocol, notes, target_machine_id, target_notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
					s.ID, s.MachineID, s.Name, s.Port, s.Protocol, s.Notes, s.TargetMachineID, s.TargetNotes)
			}
		}
	}

	if raw, ok := data["relationships"]; ok {
		var list []models.Relationship
		if err := json.Unmarshal(raw, &list); err == nil {
			for _, r := range list {
				_, _ = db.DB.Exec(`INSERT OR IGNORE INTO relationships (id, source_machine_id, target_machine_id, relation_type, source_port, target_port, notes) VALUES (?, ?, ?, ?, ?, ?, ?)`,
					r.ID, r.SourceMachineID, r.TargetMachineID, r.RelationType, r.SourcePort, r.TargetPort, r.Notes)
			}
		}
	}

	middleware.LogOperation("import", "system", nil, "json-import", "", "", c.ClientIP(), middleware.CurrentUser(c))
	c.JSON(http.StatusOK, gin.H{"message": "imported"})
}
