package com.streamplayer;

import android.content.Intent;
import android.os.Bundle;
import android.os.StrictMode;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.common.MediaItem;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector;
import androidx.media3.datasource.okhttp.OkHttpDataSource;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.hls.HlsMediaSource;
import androidx.media3.ui.PlayerView;
import androidx.media3.common.util.Util;
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;

import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.dnsoverhttps.DnsOverHttps;

@OptIn(markerClass = UnstableApi.class)
public class PlayerActivity extends AppCompatActivity {

    public static final String EXTRA_CHANNEL_NAME = "extra_channel_name";
    public static final String EXTRA_CHANNEL_URL = "extra_channel_url";

    private PlayerView playerView;
    private ProgressBar loadingIndicator;
    private TextView errorMessage;
    private TextView channelLabel;
    private Button closeButton;
    private View playerToolbar;

    private ExoPlayer player;
    private DefaultTrackSelector trackSelector;
    private String channelName;
    private String channelUrl;
    private boolean overlayVisible = true;
    private OkHttpClient okHttpClient;
    private int retryCount = 0;
    private static final int MAX_RETRIES = 3;
    private String lastStreamUrl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        StrictMode.setThreadPolicy(
                new StrictMode.ThreadPolicy.Builder().permitAll().build()
        );

        setContentView(R.layout.activity_player);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        Intent intent = getIntent();
        if (intent == null) {
            finish();
            return;
        }

        channelName = intent.getStringExtra(EXTRA_CHANNEL_NAME);
        channelUrl = intent.getStringExtra(EXTRA_CHANNEL_URL);

        if (channelName == null || channelUrl == null) {
            finish();
            return;
        }

        initViews();
        channelLabel.setText(channelName);

        // DNS configurado en StreamUrlResolver
        loadChannel();
    }

    private void initViews() {
        playerView = findViewById(R.id.player_view);
        loadingIndicator = findViewById(R.id.loading_indicator);
        errorMessage = findViewById(R.id.error_message);
        channelLabel = findViewById(R.id.player_channel_label);
        closeButton = findViewById(R.id.close_button);
        playerToolbar = findViewById(R.id.player_toolbar);

        closeButton.setOnClickListener(v -> finish());
        playerView.setOnClickListener(v -> toggleOverlay());
    }

    private void loadChannel() {
        showLoading(true);
        retryCount = 0; // Resetear contador al cargar nuevo canal
        new Thread(() -> {
            try {
                String resolvedUrl = StreamUrlResolver.resolve(channelUrl);
                runOnUiThread(() -> startPlayback(resolvedUrl));
            } catch (IOException e) {
                runOnUiThread(() -> showError("No se pudo conectar con el canal: " + e.getMessage()));
            } catch (Exception e) {
                runOnUiThread(() -> showError("Error inesperado: " + e.getMessage()));
            }
        }).start();
    }

    private void startPlayback(String streamUrl) {
        try {
            releasePlayer();
            lastStreamUrl = streamUrl; // Guardar URL para reintentos
            retryCount = 0; // Resetear contador al iniciar nueva reproducción
            DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(this)
                    .setEnableDecoderFallback(true)
                    .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON);
            
            // Configurar track selector para calidad adaptativa (no forzar máxima calidad)
            trackSelector = new DefaultTrackSelector(this);
            DefaultTrackSelector.Parameters params = trackSelector.buildUponParameters()
                    .setForceHighestSupportedBitrate(false)  // Permitir calidad adaptativa
                    .setMaxVideoBitrate(Integer.MAX_VALUE)     // Sin límite máximo de bitrate
                    .build();
            trackSelector.setParameters(params);
            
            player = new ExoPlayer.Builder(this, renderersFactory)
                    .setTrackSelector(trackSelector)
                    .setSeekForwardIncrementMs(10_000)
                    .setSeekBackIncrementMs(10_000)
                    .build();
            playerView.setPlayer(player);

            player.addListener(new Player.Listener() {
                @Override
                public void onPlaybackStateChanged(int playbackState) {
                    if (playbackState == Player.STATE_READY) {
                        showLoading(false);
                        retryCount = 0; // Resetear contador de reintentos al reproducir exitosamente
                    } else if (playbackState == Player.STATE_BUFFERING) {
                        showLoading(true);
                    }
                }

                @Override
                public void onPlayerError(PlaybackException error) {
                    String errorMsg = error.getMessage() != null ? error.getMessage() : "";
                    String detail = error.getCause() != null ?
                            error.getCause().getMessage() : "";
                    String fullError = errorMsg + " " + detail;

                    // Verificar si es un error que justifica reintento (404, conectividad, etc.)
                    boolean isRetryableError =
                        fullError.contains("404") ||
                        fullError.contains("403") ||
                        fullError.contains("timeout") ||
                        fullError.contains("Unable to connect") ||
                        fullError.contains("Network") ||
                        fullError.contains("source error") ||
                        error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED ||
                        error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT ||
                        error.errorCode == PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS;

                    if (isRetryableError && retryCount < MAX_RETRIES) {
                        retryCount++;
                        runOnUiThread(() -> {
                            showLoading(true);
                            showError("Error de conexión. Reintentando... (" + retryCount + "/" + MAX_RETRIES + ")");
                        });

                        // Reintentar después de 2 segundos
                        new android.os.Handler(android.os.Looper.getMainLooper()).postDelayed(() -> {
                            if (lastStreamUrl != null) {
                                startPlayback(lastStreamUrl);
                            } else {
                                loadChannel();
                            }
                        }, 2000);
                    } else {
                        // Mostrar error final después de agotar reintentos
                        String finalMessage = "Error al reproducir: " + fullError;
                        if (retryCount >= MAX_RETRIES) {
                            finalMessage += "\n\nSe agotaron los reintentos (" + MAX_RETRIES + ").";
                        }
                        showError(finalMessage);
                    }
                }
            });

            MediaItem mediaItem = MediaItem.fromUri(streamUrl);
            player.setMediaSource(buildMediaSource(mediaItem));
            player.prepare();
            player.setPlayWhenReady(true);
            setOverlayVisible(false);

        } catch (Exception e) {
            showError("Error al inicializar reproductor: " + e.getMessage());
        }
    }

    private void showLoading(boolean show) {
        loadingIndicator.setVisibility(show ? View.VISIBLE : View.GONE);
        errorMessage.setVisibility(View.GONE);
        playerView.setVisibility(show ? View.GONE : View.VISIBLE);
        if (show) {
            setOverlayVisible(true);
        }
    }

    private void showError(String message) {
        loadingIndicator.setVisibility(View.GONE);
        playerView.setVisibility(View.GONE);
        errorMessage.setVisibility(View.VISIBLE);
        errorMessage.setText(message);
        setOverlayVisible(true);
    }

    private void releasePlayer() {
        if (player != null) {
            player.release();
            player = null;
        }
    }

    private MediaSource buildMediaSource(MediaItem mediaItem) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Referer", channelUrl);
        headers.put("Origin", "http://streamtp10.com");
        headers.put("Accept", "*/*");
        headers.put("Connection", "keep-alive");

        String userAgent = Util.getUserAgent(this, "StreamPlayer");

        OkHttpDataSource.Factory factory = new OkHttpDataSource.Factory(provideOkHttpClient())
                .setUserAgent(userAgent)
                .setDefaultRequestProperties(headers);
        return new HlsMediaSource.Factory(factory).createMediaSource(mediaItem);
    }

    private OkHttpClient provideOkHttpClient() {
        if (okHttpClient != null) {
            return okHttpClient;
        }

        try {
            final TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[]{};
                    }
                }
            };

            final SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustAllCerts, new java.security.SecureRandom());

            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .connectTimeout(20, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .retryOnConnectionFailure(true)
                    .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
                    .hostnameVerifier((hostname, session) -> true);

            OkHttpClient bootstrap = builder.build();

            DnsOverHttps dohDns = new DnsOverHttps.Builder()
                    .client(bootstrap)
                    .url(HttpUrl.get("https://dns.google/dns-query"))
                    .bootstrapDnsHosts(
                            InetAddress.getByName("8.8.8.8"),
                            InetAddress.getByName("8.8.4.4"))
                    .build();

            okHttpClient = builder.dns(dohDns).build();
        } catch (Exception e) {
            okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(20, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .retryOnConnectionFailure(true)
                    .build();
        }

        return okHttpClient;
    }

    @Override
    protected void onStart() {
        super.onStart();
        if (player != null) {
            playerView.onResume();
        } else if (channelUrl != null) {
            loadChannel();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (player != null) {
            playerView.onResume();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (player != null) {
            playerView.onPause();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        releasePlayer();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        releasePlayer();
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    private void toggleOverlay() {
        setOverlayVisible(!overlayVisible);
    }

    private void setOverlayVisible(boolean visible) {
        overlayVisible = visible;
        playerToolbar.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    @Override
    public void onBackPressed() {
        if (!overlayVisible) {
            setOverlayVisible(true);
        } else {
            super.onBackPressed();
        }
    }
}
