package com.musicweb.player

import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.view.ViewGroup
import android.webkit.JavascriptInterface
import android.webkit.WebChromeClient
import android.webkit.WebResourceRequest
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.musicweb.player.player.PlayerService

class MainActivity : AppCompatActivity() {
    private lateinit var webView: WebView
    private val prefs by lazy { getSharedPreferences("musicweb_apk", MODE_PRIVATE) }
    private val playbackReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action != PlayerService.ACTION_PLAYBACK_STATE || !this@MainActivity::webView.isInitialized) return
            val isPlaying = intent.getBooleanExtra(PlayerService.EXTRA_IS_PLAYING, false)
            val position = intent.getLongExtra(PlayerService.EXTRA_POSITION, 0L)
            val duration = intent.getLongExtra(PlayerService.EXTRA_DURATION, 0L)
            val index = intent.getIntExtra(PlayerService.EXTRA_CURRENT_INDEX, -1)
            val name = intent.getStringExtra(PlayerService.EXTRA_TRACK_NAME).orEmpty()
            val path = intent.getStringExtra(PlayerService.EXTRA_TRACK_PATH).orEmpty()
            val error = intent.getStringExtra(PlayerService.EXTRA_ERROR).orEmpty()
            runOnUiThread {
                val script = """
                    window.__musicwebNativeUpdate && window.__musicwebNativeUpdate({
                      isPlaying: $isPlaying,
                      position: $position,
                      duration: $duration,
                      index: $index,
                      name: ${name.quoteForJs()},
                      path: ${path.quoteForJs()},
                      error: ${error.quoteForJs()}
                    });
                """.trimIndent()
                webView.evaluateJavascript(script, null)
            }
        }
    }

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        webView = WebView(this).apply {
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
            settings.apply {
                javaScriptEnabled = true
                domStorageEnabled = true
                cacheMode = WebSettings.LOAD_DEFAULT
                mediaPlaybackRequiresUserGesture = false
                mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
                allowFileAccess = true
                allowContentAccess = true
            }
            WebView.setWebContentsDebuggingEnabled(true)
            addJavascriptInterface(Bridge(), "AndroidPlayer")
            webViewClient = object : WebViewClient() {
                override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?) = false
                override fun onPageFinished(view: WebView?, url: String?) {
                    super.onPageFinished(view, url)
                    injectBridge()
                }
            }
            webChromeClient = WebChromeClient()
        }
        setContentView(webView)
        webView.loadUrl(requireBaseUrl())
    }

    override fun onBackPressed() {
        if (this::webView.isInitialized && webView.canGoBack()) webView.goBack() else super.onBackPressed()
    }

    override fun onStart() {
        super.onStart()
        ContextCompat.registerReceiver(
            this,
            playbackReceiver,
            IntentFilter(PlayerService.ACTION_PLAYBACK_STATE),
            ContextCompat.RECEIVER_NOT_EXPORTED
        )
    }

    override fun onStop() {
        unregisterReceiver(playbackReceiver)
        super.onStop()
    }

    private fun requireBaseUrl(): String {
        return prefs.getString(KEY_BASE_URL, DEFAULT_BASE_URL)?.trim().orEmpty()
            .ifBlank { DEFAULT_BASE_URL }
            .trimEnd('/')
    }

    private fun injectBridge() {
        val script = """
            (function() {
              if (window.__musicwebNativeBridgeInstalled) return;
              window.__musicwebNativeBridgeInstalled = true;
              const absoluteUrl = (url) => {
                try {
                  const parsed = new URL(url || "", window.location.href);
                  parsed.pathname = parsed.pathname
                    .split('/')
                    .map(part => encodeURIComponent(decodeURIComponent(part)))
                    .join('/');
                  return parsed.toString();
                } catch (e) {
                  return url || "";
                }
              };
              const toQueueJson = () => JSON.stringify((state.currentQueue || []).map(t => ({
                path: t.path || "",
                url: absoluteUrl(t.url || ""),
                name: t.name || "",
                folder: t.folder || ""
              })));
              const updateNativeUi = (index) => {
                if (!state.currentQueue.length) return;
                state.currentTrackIndex = index;
                const track = state.currentQueue[index];
                if (typeof updateDock === 'function') updateDock(track);
                if (typeof renderQueue === 'function') renderQueue();
                if (typeof savePlaybackState === 'function') savePlaybackState();
              };
              const sync = () => {
                if (window.AndroidPlayer && state.currentQueue && state.currentQueue.length) {
                  AndroidPlayer.setQueue(toQueueJson(), Number(state.currentTrackIndex || 0));
                }
              };
              const formatNativeTime = (ms) => {
                const total = Math.max(0, Math.floor((Number(ms) || 0) / 1000));
                const minutes = Math.floor(total / 60);
                const seconds = total % 60;
                return String(minutes).padStart(2, '0') + ':' + String(seconds).padStart(2, '0');
              };
              window.__musicwebNativeUpdate = function(payload) {
                const playing = !!payload.isPlaying;
                const toggle = document.getElementById('playToggleBtn');
                const playIcon = document.querySelector('.icon-play');
                const pauseIcon = document.querySelector('.icon-pause');
                if (toggle) {
                  toggle.classList.toggle('is-playing', playing);
                  toggle.dataset.tip = playing ? '暂停' : '播放';
                }
                if (playIcon) playIcon.classList.toggle('is-hidden', playing);
                if (pauseIcon) pauseIcon.classList.toggle('is-hidden', !playing);
                if (payload.index >= 0 && state.currentQueue && state.currentQueue[payload.index]) {
                  state.currentTrackIndex = payload.index;
                  if (typeof renderQueue === 'function') renderQueue();
                }
                const duration = Number(payload.duration || 0);
                const position = Number(payload.position || 0);
                const progress = duration > 0 ? (position / duration) * 100 : 0;
                const bar = document.getElementById('progressBar');
                if (bar) bar.value = String(Math.max(0, Math.min(100, progress)));
                const currentLabel = document.getElementById('currentTimeLabel');
                const durationLabel = document.getElementById('durationLabel');
                if (currentLabel) currentLabel.textContent = formatNativeTime(position);
                if (durationLabel) durationLabel.textContent = formatNativeTime(duration);
                if (payload.name) {
                  const title = document.getElementById('dockTitle');
                  const dockPath = document.getElementById('dockPath');
                  const nowTitle = document.getElementById('nowTitle');
                  const nowMeta = document.getElementById('nowMeta');
                  if (title) title.textContent = payload.name;
                  if (dockPath) dockPath.textContent = payload.path || '';
                  if (nowTitle) nowTitle.textContent = payload.name;
                  if (nowMeta) nowMeta.textContent = payload.path || '';
                }
              };
              window.startQueue = function(tracks, index) {
                if (!tracks || !tracks.length) return;
                state.currentQueue = [...tracks];
                updateNativeUi(index);
                AndroidPlayer.playQueue(toQueueJson(), Number(state.currentTrackIndex || 0));
              };
              window.playTrack = function(index) {
                if (!state.currentQueue.length) return;
                updateNativeUi(index);
                AndroidPlayer.playQueue(toQueueJson(), Number(state.currentTrackIndex || 0));
              };
              window.playPrevious = function() { AndroidPlayer.previous(); };
              window.playNext = function() { AndroidPlayer.next(); };
              window.nextTrack = function() { AndroidPlayer.next(); };
              const playBtn = document.getElementById('playToggleBtn');
              if (playBtn && !playBtn.dataset.nativeBound) {
                playBtn.dataset.nativeBound = '1';
                playBtn.onclick = function() { AndroidPlayer.toggle(); };
              }
              const prevBtn = document.getElementById('prevBtn');
              if (prevBtn && !prevBtn.dataset.nativeBound) {
                prevBtn.dataset.nativeBound = '1';
                prevBtn.onclick = function() { AndroidPlayer.previous(); };
              }
              const nextBtn = document.getElementById('nextBtn');
              if (nextBtn && !nextBtn.dataset.nativeBound) {
                nextBtn.dataset.nativeBound = '1';
                nextBtn.onclick = function() { AndroidPlayer.next(); };
              }
              sync();
            })();
        """.trimIndent()
        webView.evaluateJavascript(script, null)
    }

    inner class Bridge {
        @JavascriptInterface
        fun setQueue(queueJson: String, index: Int) {
            val intent = Intent(this@MainActivity, PlayerService::class.java).apply {
                action = PlayerService.ACTION_SET_QUEUE
                putExtra(PlayerService.EXTRA_QUEUE_JSON, queueJson)
                putExtra(PlayerService.EXTRA_INDEX, index)
            }
            startService(intent)
        }

        @JavascriptInterface
        fun playQueue(queueJson: String, index: Int) {
            val intent = Intent(this@MainActivity, PlayerService::class.java).apply {
                action = PlayerService.ACTION_PLAY_QUEUE
                putExtra(PlayerService.EXTRA_QUEUE_JSON, queueJson)
                putExtra(PlayerService.EXTRA_INDEX, index)
            }
            ContextCompat.startForegroundService(this@MainActivity, intent)
        }

        @JavascriptInterface
        fun toggle() {
            startService(Intent(this@MainActivity, PlayerService::class.java).apply {
                action = PlayerService.ACTION_TOGGLE
            })
        }

        @JavascriptInterface
        fun next() {
            startService(Intent(this@MainActivity, PlayerService::class.java).apply {
                action = PlayerService.ACTION_NEXT
            })
        }

        @JavascriptInterface
        fun previous() {
            startService(Intent(this@MainActivity, PlayerService::class.java).apply {
                action = PlayerService.ACTION_PREVIOUS
            })
        }

        @JavascriptInterface
        fun saveBaseUrl(url: String) {
            prefs.edit().putString(KEY_BASE_URL, url.trimEnd('/')).apply()
        }
    }

    companion object {
        const val KEY_BASE_URL = "base_url"
        const val DEFAULT_BASE_URL = "http://110.42.102.94:8006/"
    }
}

private fun String.quoteForJs(): String {
    return buildString {
        append('"')
        this@quoteForJs.forEach { char ->
            when (char) {
                '\\' -> append("\\\\")
                '"' -> append("\\\"")
                '\n' -> append("\\n")
                '\r' -> append("\\r")
                '\t' -> append("\\t")
                else -> append(char)
            }
        }
        append('"')
    }
}
