package com.streamplayer;

import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Informa al dashboard qué dispositivos tienen instalada la app y permite bloquearlos remotamente.
 */
public class DeviceRegistry {

    public interface Callback {
        void onAllowed();

        void onBlocked(String reason, String tokenPart);

        void onError(String message);
    }

    private static final String TAG = "DeviceRegistry";
    private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    private final Context appContext;
    private final OkHttpClient httpClient;
    private final ExecutorService executorService;
    private final Handler mainHandler = new Handler(Looper.getMainLooper());

    public DeviceRegistry(Context context) {
        this.appContext = context.getApplicationContext();
        // Usar NetworkUtils para obtener cliente con DNS over HTTPS configurado
        this.httpClient = NetworkUtils.getClient();
        this.executorService = Executors.newSingleThreadExecutor();
    }

    public void syncDevice(Callback callback) {
        if (TextUtils.isEmpty(BuildConfig.DEVICE_REGISTRY_URL)) {
            postAllowed(callback);
            return;
        }
        executorService.execute(() -> {
            try {
                JSONObject payload = new JSONObject();
                payload.put("deviceId", getDeviceId());
                payload.put("deviceName", Build.MODEL);
                payload.put("model", Build.MODEL);
                payload.put("manufacturer", capitalize(Build.MANUFACTURER));
                payload.put("osVersion", Build.VERSION.RELEASE + " (API " + Build.VERSION.SDK_INT + ")");
                payload.put("appVersionName", BuildConfig.VERSION_NAME);
                payload.put("appVersionCode", BuildConfig.VERSION_CODE);

                String endpoint = sanitizeBaseUrl(BuildConfig.DEVICE_REGISTRY_URL) + "/api/devices/register";
                RequestBody body = RequestBody.create(payload.toString(), JSON);
                Request request = new Request.Builder()
                        .url(endpoint)
                        .post(body)
                        .build();
                try (Response response = httpClient.newCall(request).execute()) {
                    if (!response.isSuccessful() || response.body() == null) {
                        throw new IOException("HTTP " + response.code());
                    }
                    String responseText = response.body().string();
                    
                    // Validar que no sea HTML antes de parsear
                    if (responseText != null) {
                        String trimmed = responseText.trim();
                        if (trimmed.startsWith("<!") || trimmed.startsWith("<html")) {
                            throw new IOException("El servidor devolvió HTML en lugar de JSON");
                        }
                    }
                    
                    JSONObject json = new JSONObject(responseText);
                    JSONObject deviceJson = json.optJSONObject("device");
                    JSONObject verificationJson = json.optJSONObject("verification");
                    boolean blocked = json.optBoolean("blocked", false);
                    String reason = json.optString("message");
                    if (TextUtils.isEmpty(reason) && deviceJson != null) {
                        reason = deviceJson.optString("notes", "");
                    }
                    String tokenPart = "";
                    if (verificationJson != null) {
                        boolean verificationRequired = verificationJson.optBoolean("required", false);
                        blocked = blocked || verificationRequired;
                        tokenPart = verificationJson.optString("clientTokenPart", "");
                    }
                    if (blocked) {
                        postBlocked(callback, reason, tokenPart);
                    } else {
                        postAllowed(callback);
                    }
                }
            } catch (IOException | JSONException e) {
                Log.w(TAG, "Device sync error", e);
                postError(callback, e.getMessage());
            }
        });
    }

    private String sanitizeBaseUrl(String base) {
        if (TextUtils.isEmpty(base)) {
            return "";
        }
        if (base.endsWith("/")) {
            return base.substring(0, base.length() - 1);
        }
        return base;
    }

    private String getDeviceId() {
        String id = Settings.Secure.getString(appContext.getContentResolver(),
                Settings.Secure.ANDROID_ID);
        if (TextUtils.isEmpty(id)) {
            id = Build.MODEL + "-" + Build.BOARD + "-" + BuildConfig.VERSION_CODE;
        }
        return id;
    }

    private String capitalize(String value) {
        if (TextUtils.isEmpty(value)) {
            return "";
        }
        return value.substring(0, 1).toUpperCase(Locale.getDefault())
                + value.substring(1);
    }

    public void release() {
        executorService.shutdownNow();
    }

    private void postAllowed(Callback callback) {
        if (callback == null) {
            return;
        }
        mainHandler.post(callback::onAllowed);
    }

    private void postBlocked(Callback callback, String reason, String tokenPart) {
        if (callback == null) {
            return;
        }
        String reasonText = reason == null ? "" : reason;
        String token = tokenPart == null ? "" : tokenPart;
        mainHandler.post(() -> callback.onBlocked(reasonText, token));
    }

    private void postError(Callback callback, String message) {
        if (callback == null) {
            return;
        }
        mainHandler.post(() -> callback.onError(message));
    }
}
