package pjlink

import (
	"bufio"
	"crypto/md5"
	"errors"
	"fmt"
	"net"
	"strings"
	"time"
)

var (
	ErrAuthFailed   = errors.New("授权验证失败")
	ErrCommandError = errors.New("命令执行异常")
)

type Client struct {
	Host     string
	Port     string
	Password string
	ID       string
	conn     net.Conn
}

func NewClient(host, port, password, id string) *Client {
	return &Client{
		Host:     host,
		Port:     port,
		Password: password,
		ID:       id,
	}
}

func (c *Client) connect() error {
	address := net.JoinHostPort(c.Host, c.Port)
	conn, err := net.DialTimeout("tcp", address, 5*time.Second)
	if err != nil {
		return fmt.Errorf("连接异常: %w", err)
	}
	c.conn = conn

	// Read challenge
	reader := bufio.NewReader(c.conn)
	response, err := reader.ReadString('\r')
	if err != nil {
		c.close()
		return fmt.Errorf("读取异常: %w", err)
	}

	// Handle authentication
	if strings.HasPrefix(response, "PJLINK 1") {
		if c.Password == "" {
			c.close()
			return ErrAuthFailed
		}

		challenge := strings.TrimSpace(strings.Split(response, " ")[2])
		authString := fmt.Sprintf("%s%s", challenge, c.Password)
		hashed := md5.Sum([]byte(authString))
		authHash := fmt.Sprintf("%x", hashed)

		_, err = fmt.Fprintf(c.conn, "%s\r", authHash)
		if err != nil {
			c.close()
			return fmt.Errorf("写入异常: %w", err)
		}

		authResponse, err := reader.ReadString('\r')
		if err != nil || !strings.Contains(authResponse, "OK") {
			c.close()
			return ErrAuthFailed
		}
	}

	return nil
}

func (c *Client) sendCommand(command string) (string, error) {
	if c.conn == nil {
		return "", errors.New("not connected")
	}

	fullCommand := fmt.Sprintf("%%%s%s\r", c.ID, command)
	_, err := c.conn.Write([]byte(fullCommand))
	if err != nil {
		return "", err
	}

	reader := bufio.NewReader(c.conn)
	response, err := reader.ReadString('\r')
	if err != nil {
		return "", err
	}

	// Remove prefix and parse response
	parts := strings.SplitN(response, "=", 2)
	if len(parts) < 2 {
		return "", ErrCommandError
	}

	result := strings.TrimSpace(parts[1])
	if result == "ERR1" {
		return "", ErrAuthFailed
	} else if result == "ERR2" {
		return "", ErrCommandError
	} else if result == "ERR3" {
		return "YES", nil
	}

	return result, nil
}

func (c *Client) PowerOn() (string, error) {
	err := c.connect()
	if err != nil {
		return "", fmt.Errorf("连接异常: %w", err)
	}
	defer c.close()

	response, err := c.sendCommand("POWR 1")
	if err != nil {
		return "", err
	}

	if response == "YES" {
		return response, nil
	} else if response != "OK" {
		return response, fmt.Errorf("unexpected response: %s", response)
	}
	return response, nil
}

func (c *Client) PowerOff() (string, error) {
	err := c.connect()
	if err != nil {
		return "", fmt.Errorf("连接异常: %w", err)
	}
	defer c.close()

	response, err := c.sendCommand("POWR 0")
	if err != nil {
		return "", err
	}

	if response == "YES" {
		return response, nil
	} else if response != "OK" {
		return response, fmt.Errorf("unexpected response: %s", response)
	}
	return response, nil
}

func (c *Client) close() {
	if c.conn != nil {
		c.conn.Close()
		c.conn = nil
	}
}
