package me.qwq.doghouse.util;

import java.io.IOException;
import java.net.Proxy;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.redisson.api.RBucket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
import me.qwq.dogface.Dogface;
import me.qwq.doghouse.annotation.StaticAttribute;
import me.qwq.doghouse.component.Rk;
import me.qwq.doghouse.entity.config.NetworkConfig;
import me.qwq.doghouse.entity.config.SiteConfig;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

@StaticAttribute
@Component
@DependsOn("siteConfig")
@Slf4j
public class GravatarUtils {
    
    private final ConcurrentHashMap<String, Lock> lockMap = new ConcurrentHashMap<>();

    @Autowired
    SiteConfig siteConfig;
    
    @Autowired
    NetworkConfig networkConfig;
    
    @Autowired
    Dogface dogface;
    
    /**
     * 通过 email 和 size 获取代理的 API Gravatar 链接
     * @param mail
     * @param size
     * @return
     */
    public static String getAvatarUrlProxied(String mail, int size) {
        String privateHash = Rk.Gravatar.prepareDogHash(mail);
        return getProxyAvatarUrl(privateHash, size);
    }

    public static String getProxyAvatarUrl(String emailHash, Integer size) {
        if (size == null || size <= 0) size = 100;
        return getProxyAvatarUrl(emailHash) + "/" + size;
    }
    
    public static String getProxyAvatarUrl(String emailHash) {
        return "/api/v2/gravatar/get/" + emailHash;
    }
    
    @Async
    public Future<byte[]> getReversedProxyGravatarAsync(String privateHash, int size, boolean fromCache) {
        return CompletableFuture.completedFuture(getProxyGravatar(privateHash, size, fromCache));
    }
    
    public byte[] getProxyGravatar(String dogHash, int size, boolean fromCache) {
        
        RBucket<Object> gravatarBucket = Rk.Gravatar.getGravatarBucket(dogHash, size);
        
        byte[] cache = (byte[]) gravatarBucket.get();
        if (fromCache && cache != null && cache.length != 0) return cache;
        
        String realHash = Rk.Gravatar.getRealHash(dogHash);
        if (realHash == null) {
            log.warn("无法找到 dog hash {} 对应的 real hash", dogHash);
            return null;
        }
        String url = siteConfig.getGravatarUrl() + realHash + "?s=" + size + "&r=G&d=404";
        
        if (url != null && url.startsWith("//")) {
            url = url.substring(2);
        }
        
        url = "https://" + url;
        
        Lock lock = lockMap.computeIfAbsent(gravatarBucket.getName(), k -> new ReentrantLock());
        
        try {
            lock.lock();
            cache = (byte[]) gravatarBucket.get();
            if (!fromCache || cache == null || cache.length == 0) {
                // 此时再去请求 HTTP
                Proxy proxy = networkConfig.getProxy();
                OkHttpClient client = new OkHttpClient.Builder().proxy(proxy).build();
                Request request = new Request.Builder()
                        .url(url)
                        .get().build();
                final Call call = client.newCall(request);
                try (Response response = call.execute()) {
                    if (response.code() == 404) {
                        cache = dogface.getDogavatar(realHash, size);
                        gravatarBucket.set(cache, Duration.ofMinutes(10L));
                    }
                    else {
                        cache = response.body().bytes();
                        if (cache.length == 0) {
                            log.warn("Gravatar body length is 0");
                        }
                        else {
                            gravatarBucket.set(cache, Duration.ofMinutes(10L));
                        }
                    }
                }
                catch (IOException e) {
                    log.error("代理获取 Gravatar 错误: {}", e.getMessage());
                    cache = dogface.getDogavatar(realHash, size);
                    // 网络原因导致的错误设置临时头像过期时间为 30s
                    if (cache != null)
                        gravatarBucket.set(cache, Duration.ofSeconds(30L));
                    else return cache;
                }
            }
        }
        finally {
            lock.unlock();
        }
        
        return (byte[])gravatarBucket.get();
    }
    
}