package org.kne.cloud.network;

import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;

import org.kne.cloud.network.ipv6.IPv6Address;

/**
 * 高性能IPv6套接字地址实现，替代Java原生的InetSocketAddress
 * 大幅减少GC压力和提高网络栈性能
 */
public final class IPv6SocketAddress  {
    

	private static final long serialVersionUID = 1L;
    
    private final IPv6Address address;
    private final int port;
    
    // 常用常量
    public static final IPv6SocketAddress ANY = new IPv6SocketAddress(IPv6Address.UNSPECIFIED, 0);
    
    // 构造方法
    public IPv6SocketAddress(IPv6Address address, int port ) {
        if (address == null) {
            throw new IllegalArgumentException("Address cannot be null");
        }
        if (port < 0 || port > 65535) {
            throw new IllegalArgumentException("Port out of range: " + port);
        }
        this.address = address;
        this.port = port;
    }
    
    /**
     * 从IPv6地址和端口创建
     */
    public static IPv6SocketAddress valueOf(IPv6Address address, int port) {
        return new IPv6SocketAddress(address, port);
    }
    
    /**
     * 从两个long和端口创建（最高性能）
     */
    public static IPv6SocketAddress valueOf(long high, long low, int port) {
        return new IPv6SocketAddress(IPv6Address.valueOf(high, low), port);
    }
    
    /**
     * 从byte[16]和端口创建
     */
    public static IPv6SocketAddress valueOf(byte[] addressBytes, int port) {
        return new IPv6SocketAddress(IPv6Address.valueOf(addressBytes), port);
    }
    
    /**
     * 从ByteBuffer创建（零拷贝友好）
     */
    public static IPv6SocketAddress valueOf(ByteBuffer buffer) {
        if (buffer.remaining() < 18) { // 16字节地址 + 2字节端口
            throw new IllegalArgumentException("Buffer must have at least 18 bytes remaining");
        }
        
        long high = buffer.getLong();
        long low = buffer.getLong();
        int port = buffer.getShort() & 0xFFFF;
        
        return valueOf(high, low, port);
    }
    
    /**
     * 从ByteBuffer指定位置创建
     */
    public static IPv6SocketAddress valueOf(int offset, ByteBuffer buffer) {
        if (buffer.remaining() < offset + 18) {
            throw new IllegalArgumentException("Buffer too small");
        }
        
        long high = buffer.getLong(offset);
        long low = buffer.getLong(offset + 8);
        int port = buffer.getShort(offset + 16) & 0xFFFF;
        
        return valueOf(high, low, port);
    }
    
    /**
     * 从Java InetSocketAddress转换
     */
    public static IPv6SocketAddress valueOf(InetSocketAddress inetSocketAddress) {
        if (inetSocketAddress == null) {
            throw new IllegalArgumentException("InetSocketAddress cannot be null");
        }
        
        IPv6Address addr = IPv6Address.valueOf(inetSocketAddress.getAddress());
        int port = inetSocketAddress.getPort();
        
        return new IPv6SocketAddress(addr, port);
    }
    
    /**
     * 从字符串解析（格式: [ipv6]:port 或 ipv6:port）
     */
    public static IPv6SocketAddress valueOf(String socketAddress) {
        if (socketAddress == null || socketAddress.isEmpty()) {
            throw new IllegalArgumentException("Invalid socket address string");
        }
        
        try {
            // 处理[ipv6]:port格式
            if (socketAddress.startsWith("[")) {
                int closeBracket = socketAddress.indexOf(']');
                if (closeBracket == -1) {
                    throw new IllegalArgumentException("Invalid IPv6 socket address format");
                }
                
                String ipPart = socketAddress.substring(1, closeBracket);
                String portPart = socketAddress.substring(closeBracket + 1);
                
                if (!portPart.startsWith(":")) {
                    throw new IllegalArgumentException("Invalid IPv6 socket address format");
                }
                
                IPv6Address address = IPv6Address.valueOf(ipPart);
                int port = Integer.parseInt(portPart.substring(1));
                
                return valueOf(address, port);
            } else {
                // 处理ipv6:port格式（简单情况）
                int lastColon = socketAddress.lastIndexOf(':');
                if (lastColon == -1) {
                    throw new IllegalArgumentException("Invalid IPv6 socket address format");
                }
                
                String ipPart = socketAddress.substring(0, lastColon);
                String portPart = socketAddress.substring(lastColon + 1);
                
                IPv6Address address = IPv6Address.valueOf(ipPart);
                int port = Integer.parseInt(portPart);
                
                return valueOf(address, port);
            }
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid IPv6 socket address: " + socketAddress, e);
        }
    }
    
    /**
     * 创建未解析的地址（带hostname）
     * @throws UnknownHostException 
     */
    public static IPv6SocketAddress createUnresolved(String hostname, int port) throws UnknownHostException {
        if (hostname == null || hostname.isEmpty()) {
            throw new IllegalArgumentException("Hostname cannot be null or empty");
        }
        if (port < 0 || port > 65535) {
            throw new IllegalArgumentException("Port out of range: " + port);
        }
        
        return new IPv6SocketAddress(IPv6Address.valueOf ( hostname), port);
    }
    
    // 核心getter方法
    public IPv6Address getAddress() {
        return address;
    }
    
    public int getPort() {
        return port;
    }
    
    /**
     * 转换为byte数组（18字节：16字节地址 + 2字节端口）
     */
    public byte[] toByteArray() {
        byte[] bytes = new byte[18];
        toByteArray(bytes, 0);
        return bytes;
    }
    
    /**
     * 写入到现有byte数组
     */
    public void toByteArray(byte[] dest, int offset) {
        if (dest.length - offset < 18) {
            throw new IllegalArgumentException("Destination array too small");
        }
        
        address.toByteArray(dest, offset);
        dest[offset + 16] = (byte) (port >> 8);
        dest[offset + 17] = (byte) port;
    }
    
    /**
     * 写入到ByteBuffer（高性能网络操作）
     */
    public void writeTo(ByteBuffer buffer) {
        address.writeTo(buffer);
        buffer.putShort((short) port);
    }
    
    /**
     * 写入到ByteBuffer指定位置
     */
    public void writeTo(int offset, ByteBuffer buffer) {
        address.writeTo(offset, buffer);
        buffer.putShort(offset + 16, (short) port);
    }
    
    /**
     * 转换为Java InetSocketAddress（兼容性方法）
     */
    public InetSocketAddress toInetSocketAddress() {
            Inet6Address inet6Addr = address.toInet6Address();
            return new InetSocketAddress(inet6Addr, port);
    }
    
    // 实用方法
    
    /**
     * 检查是否为通配符地址（0.0.0.0:0）
     */
    public boolean isWildcardAddress() {
        return address.equals(IPv6Address.UNSPECIFIED) && port == 0;
    }
    
    /**
     * 检查是否为环回地址
     */
    public boolean isLoopbackAddress() {
        return address.isLoopbackAddress();
    }
    
    /**
     * 检查是否为多播地址
     */
    public boolean isMulticastAddress() {
        return address.isMulticastAddress();
    }
    
    /**
     * 检查是否为链路本地地址
     */
    public boolean isLinkLocalAddress() {
        return address.isLinkLocalAddress();
    }
    
    /**
     * 检查是否为站点本地地址
     */
    public boolean isSiteLocalAddress() {
        return address.isSiteLocalAddress();
    }
    
    /**
     * 获取多播地址的scope
     */
    public int getMulticastScope() {
        return address.getMulticastScope();
    }
    
    // 路由相关的实用方法
    
    /**
     * 检查地址是否在指定网络内
     */
    public boolean isInNetwork(IPv6Address network, int prefixLength) {
        return address.isInNetwork(network, prefixLength);
    }
    
    /**
     * 应用网络掩码
     */
    public IPv6SocketAddress maskWith(IPv6Address mask) {
        return valueOf(address.maskWith(mask), port);
    }
    
    // 比较和哈希
    
    
    @Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		result = prime * result + port;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		IPv6SocketAddress other = (IPv6SocketAddress) obj;
		if (address == null) {
			if (other.address != null)
				return false;
		} else if (!address.equals(other.address))
			return false;
		if (port != other.port)
			return false;
		return true;
	}
   
    
    @Override
    public String toString() {
            // 对于IPv6地址，使用方括号括起来
            return "[" + address.toString() + "]:" + port;
    }
    
    /**
     * 转换为压缩形式的字符串
     */
    public String toCompressedString() {
            return "[" + address.toCompressedString() + "]:" + port;
    }
    
    
}