package siteMonitor

import (
	"ALLinSSL/backend/public"
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"strings"
	"time"
)

// SSLInfo 定义结果结构体
type SSLInfo struct {
	Target          string
	HTTPStatus      int
	HTTPStatusText  string
	Domains         []string
	Issuer          string
	NotBefore       string
	NotAfter        string
	DaysRemaining   int
	CertificateOK   bool
	CertificateNote string
}

func GetSqlite() (*public.Sqlite, error) {
	s, err := public.NewSqlite("data/data.db", "")
	if err != nil {
		return nil, err
	}
	s.Connect()
	s.TableName = "site_monitor"
	return s, nil
}

func GetList(search string, p, limit int64) ([]map[string]any, int, error) {
	var data []map[string]any
	var count int64
	s, err := GetSqlite()
	if err != nil {
		return data, 0, err
	}
	defer s.Close()

	var limits []int64
	if p >= 0 && limit >= 0 {
		limits = []int64{0, limit}
		if p > 1 {
			limits[0] = (p - 1) * limit
			limits[1] = p * limit
		}
	}

	if search != "" {
		count, err = s.Where("name like ? or site_domain like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Count()
		data, err = s.Where("name like ? or site_domain like ?", []interface{}{"%" + search + "%", "%" + search + "%"}).Order("update_time", "desc").Limit(limits).Select()
	} else {
		count, err = s.Count()
		data, err = s.Order("update_time", "desc").Limit(limits).Select()
	}
	if err != nil {
		return data, 0, err
	}
	for _, v := range data {
		v["domain"] = v["site_domain"]
	}

	return data, int(count), nil
}

func AddMonitor(name, domain, reportType string, cycle int) error {
	s, err := GetSqlite()
	if err != nil {
		return err
	}
	defer s.Close()
	info, err := CheckWebsite(domain)
	if err != nil {
		return err
	}
	_, err = s.Insert(map[string]any{
		"name":        name,
		"site_domain": domain,
		"report_type": reportType,
		"cycle":       cycle,
		"state":       info.HTTPStatusText,
		"ca":          info.Issuer,
		"cert_domain": strings.Join(info.Domains, ","),
		"end_time":    info.NotAfter,
		"end_day":     info.DaysRemaining,
		"create_time": time.Now().Format("2006-01-02 15:04:05"),
		"update_time": time.Now().Format("2006-01-02 15:04:05"),
		"last_time":   time.Now().Format("2006-01-02 15:04:05"),
		"active":      1,
	})
	if err != nil {
		return err
	}
	return nil
}

func UpdMonitor(id, name, domain, reportType string, cycle int) error {
	s, err := GetSqlite()
	if err != nil {
		return err
	}
	defer s.Close()

	info, err := CheckWebsite(domain)
	if err != nil {
		return err
	}
	_, err = s.Where("id=?", []interface{}{id}).Update(map[string]any{
		"name":        name,
		"site_domain": domain,
		"report_type": reportType,
		"cycle":       cycle,
		"state":       info.HTTPStatusText,
		"ca":          info.Issuer,
		"cert_domain": strings.Join(info.Domains, ","),
		"end_time":    info.NotAfter,
		"end_day":     info.DaysRemaining,
		"update_time": time.Now().Format("2006-01-02 15:04:05"),
		"last_time":   time.Now().Format("2006-01-02 15:04:05"),
		"active":      1,
	})
	if err != nil {
		return err
	}
	return nil
}

func DelMonitor(id string) error {
	s, err := GetSqlite()
	if err != nil {
		return err
	}
	defer s.Close()
	_, err = s.Where("id=?", []interface{}{id}).Delete()
	if err != nil {
		return err
	}
	return nil
}

func SetMonitor(id string, active int) error {
	s, err := GetSqlite()
	if err != nil {
		return err
	}
	defer s.Close()
	_, err = s.Where("id=?", []interface{}{id}).Update(map[string]any{
		"active":      active,
		"update_time": time.Now().Format("2006-01-02 15:04:05"),
	})
	if err != nil {
		return err
	}
	return nil
}

func UpdInfo(id, domain string, s *public.Sqlite, reportType string) error {
	info, errCheck := CheckWebsite(domain)
	now := time.Now()
	updateData := map[string]any{
		"state":           info.HTTPStatusText,
		"ca":              info.Issuer,
		"cert_domain":     strings.Join(info.Domains, ","),
		"end_time":        info.NotAfter,
		"end_day":         info.DaysRemaining,
		"last_time":       now.Format("2006-01-02 15:04:05"),
		"except_end_time": now.Format("2006-01-02 15:04:05"),
	}
	if errCheck != nil {
		updateData["state"] = "异常"
		// return err
	} else {
		if info.HTTPStatus != 0 && info.CertificateOK != false {
			delete(updateData, "except_end_time")
		} else {
			errCheck = fmt.Errorf("证书异常")
		}
	}
	_, err := s.Where("id=?", []interface{}{id}).Update(updateData)
	if err != nil {
		return err
	}
	return errCheck
}

// CheckWebsite 实际检测函数
func CheckWebsite(target string) (*SSLInfo, error) {
	result := &SSLInfo{Target: target}

	// 验证格式是否是 IP 或域名
	if net.ParseIP(target) == nil {
		if _, err := net.LookupHost(target); err != nil {
			return result, fmt.Errorf("无效域名或 IP：%v", err)
		}
	}

	hostPort := net.JoinHostPort(target, "443")

	// result := &SSLInfo{Target: target}

	// 1. TLS 连接（先做，否则无 HTTPS 支持直接失败）
	conn, err := tls.Dial("tcp", hostPort, &tls.Config{
		InsecureSkipVerify: true,
	})
	if err != nil {
		return result, fmt.Errorf("目标不支持 HTTPS：%v", err)
	}
	defer conn.Close()

	// 发送 HTTPS 请求检测状态
	resp, err := http.Get("https://" + target)
	if err != nil {
		result.HTTPStatus = 0
		result.HTTPStatusText = "异常"
	} else {
		result.HTTPStatus = resp.StatusCode
		result.HTTPStatusText = "正常"
		resp.Body.Close()
	}

	// 获取证书
	cert := conn.ConnectionState().PeerCertificates[0]
	result.Domains = cert.DNSNames
	result.Issuer = cert.Issuer.CommonName
	result.NotBefore = cert.NotBefore.Format("2006-01-02 15:04:05")
	result.NotAfter = cert.NotAfter.Format("2006-01-02 15:04:05")
	result.DaysRemaining = int(cert.NotAfter.Sub(time.Now()).Hours() / 24)

	now := time.Now()
	switch {
	case now.Before(cert.NotBefore):
		result.CertificateOK = false
		result.CertificateNote = "尚未生效"
	case now.After(cert.NotAfter):
		result.CertificateOK = false
		result.CertificateNote = "已过期"
	default:
		result.CertificateOK = true
		result.CertificateNote = "有效"
	}

	return result, nil
}
