package com.foxx.androidcast.display;

import android.content.Context;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.Display;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Tracks wired / external displays (USB-C HDMI, presentation, etc.) for roadmap D.
 * Does not perform capture — informs UI and future capture routing.
 */
public final class WiredDisplayMonitor implements DisplayManager.DisplayListener {

    public static final class ExternalDisplayInfo {
        public final int displayId;
        public final String name;
        public final int widthPx;
        public final int heightPx;
        public final int flags;

        ExternalDisplayInfo(Display display) {
            displayId = display.getDisplayId();
            name = display.getName() != null ? display.getName() : ("Display " + displayId);
            DisplayMetrics m = new DisplayMetrics();
            display.getRealMetrics(m);
            widthPx = m.widthPixels;
            heightPx = m.heightPixels;
            flags = display.getFlags();
        }

        public boolean likelyHdmiOrWired() {
            return (flags & Display.FLAG_PRESENTATION) != 0
                    || (flags & Display.FLAG_SECURE) != 0
                    || displayId != Display.DEFAULT_DISPLAY;
        }
    }

    public interface Listener {
        void onWiredDisplaysChanged(List<ExternalDisplayInfo> externalDisplays);
    }

    private static volatile WiredDisplayMonitor instance;

    private final DisplayManager displayManager;
    private final Handler mainHandler;
    private final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
    private volatile List<ExternalDisplayInfo> externalDisplays = Collections.emptyList();
    private boolean registered;

    public static WiredDisplayMonitor getInstance(Context context) {
        if (instance == null) {
            synchronized (WiredDisplayMonitor.class) {
                if (instance == null) {
                    instance = new WiredDisplayMonitor(context.getApplicationContext());
                }
            }
        }
        return instance;
    }

    private WiredDisplayMonitor(Context context) {
        displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
        mainHandler = new Handler(Looper.getMainLooper());
        refresh();
    }

    public void addListener(Listener listener) {
        if (listener != null) {
            listeners.add(listener);
            listener.onWiredDisplaysChanged(externalDisplays);
        }
    }

    public void removeListener(Listener listener) {
        listeners.remove(listener);
    }

    public synchronized void ensureRegistered() {
        if (registered || displayManager == null) {
            return;
        }
        displayManager.registerDisplayListener(this, mainHandler);
        registered = true;
        refresh();
    }

    public synchronized void unregister() {
        if (!registered || displayManager == null) {
            return;
        }
        displayManager.unregisterDisplayListener(this);
        registered = false;
    }

    public List<ExternalDisplayInfo> getExternalDisplays() {
        return externalDisplays;
    }

    public boolean hasExternalDisplay() {
        return !externalDisplays.isEmpty();
    }

    public String getSummaryLine() {
        if (externalDisplays.isEmpty()) {
            return "No external display detected (USB-C HDMI will not work until OS sees a second screen).";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(externalDisplays.size()).append(" external display(s): ");
        for (int i = 0; i < externalDisplays.size(); i++) {
            if (i > 0) {
                sb.append("; ");
            }
            ExternalDisplayInfo info = externalDisplays.get(i);
            sb.append(info.name).append(" ").append(info.widthPx).append("×").append(info.heightPx);
        }
        return sb.toString();
    }

    @Override
    public void onDisplayAdded(int displayId) {
        if (displayId != Display.DEFAULT_DISPLAY) {
            refresh();
        }
    }

    @Override
    public void onDisplayRemoved(int displayId) {
        if (displayId != Display.DEFAULT_DISPLAY) {
            refresh();
        }
    }

    @Override
    public void onDisplayChanged(int displayId) {
        if (displayId != Display.DEFAULT_DISPLAY) {
            refresh();
        }
    }

    private void refresh() {
        List<ExternalDisplayInfo> next = scan();
        externalDisplays = next;
        for (Listener l : listeners) {
            l.onWiredDisplaysChanged(next);
        }
    }

    private List<ExternalDisplayInfo> scan() {
        if (displayManager == null) {
            return Collections.emptyList();
        }
        Display[] displays = displayManager.getDisplays();
        if (displays == null || displays.length == 0) {
            return Collections.emptyList();
        }
        List<ExternalDisplayInfo> out = new ArrayList<>();
        for (Display d : displays) {
            if (d == null || d.getDisplayId() == Display.DEFAULT_DISPLAY) {
                continue;
            }
            out.add(new ExternalDisplayInfo(d));
        }
        return Collections.unmodifiableList(out);
    }
}
