package com.ruoyi.app.omgpay;

import org.springframework.stereotype.Component;

import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/** Renders a fixed, escaped page that opens the configured App route and keeps a manual fallback button. */
@Component
public class OmgPaymentReturnPageRenderer {
    private static final String UNI_WEB_VIEW_BRIDGE = "/pay/omg/bridge.js";
    private final OmgPaymentProperties properties;

    public OmgPaymentReturnPageRenderer(OmgPaymentProperties properties) {
        this.properties = properties;
    }

    public OmgPaymentReturnPage success(String orderId) {
        String appLink = buildAppLink(orderId);
        if (appLink == null) {
            return error(503, "App 返回網址尚未設定");
        }
        String appRoute = buildAppRoute(appLink);
        String escapedLink = escapeHtml(appLink);
        String escapedRoute = escapeHtml(appRoute);
        String html = page("正在返回 App", "請稍候，App 開啟後會確認最終付款狀態。",
                "<a id=\"open-app\" href=\"" + escapedLink + "\" data-app-route=\""
                        + escapedRoute + "\">返回 App</a>"
                        + "<script src=\"" + UNI_WEB_VIEW_BRIDGE + "\"></script>"
                        + diagnosticScript());
        return new OmgPaymentReturnPage(200, html);
    }

    public OmgPaymentReturnPage error(int statusCode, String message) {
        return new OmgPaymentReturnPage(statusCode,
                page("無法返回 App", escapeHtml(message), ""));
    }

    private String buildAppLink(String orderId) {
        String base = properties.safeAppReturnUrlOrNull();
        if (base == null) {
            return null;
        }
        return base + "?ddId=" + encode(orderId);
    }

    private static String buildAppRoute(String appLink) {
        URI uri = URI.create(appLink);
        return "/" + uri.getHost() + uri.getPath() + "?" + uri.getRawQuery();
    }

    private static String page(String title, String message, String action) {
        return "<!doctype html><html lang=\"zh-Hant-TW\"><head><meta charset=\"utf-8\">"
                + "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"
                + "<title>" + title + "</title><style>body{font-family:system-ui,sans-serif;"
                + "margin:0;padding:32px;background:#f7f7f7;color:#222;text-align:center}main{max-width:480px;"
                + "margin:15vh auto;background:#fff;padding:32px;border-radius:16px}a{display:inline-block;"
                + "margin-top:20px;padding:12px 24px;background:#1677ff;color:#fff;text-decoration:none;"
                + "border-radius:8px}</style></head><body><main><h1>" + title + "</h1><p>"
                + message + "</p>" + action + "</main></body></html>";
    }

    private static String diagnosticScript() {
        return "<script>(function(){'use strict';"
                + "var PREFIX='[OMG-RETURN]',startedAt=Date.now(),link=document.getElementById('open-app'),"
                + "target=link.href,appRoute=link.getAttribute('data-app-route'),handoffObserved=false,bridgeStarted=false,schemeStarted=false;"
                + "function targetSummary(value){try{var parsed=new URL(value);return {protocol:parsed.protocol,host:parsed.host,pathname:parsed.pathname};}"
                + "catch(error){return {parseError:true};}}"
                + "function orderRef(value){try{var id=new URL(value).searchParams.get('ddId')||'';return id?'***'+id.slice(-4):'';}"
                + "catch(error){return '';}}"
                + "function routePath(value){return String(value||'').split('?')[0];}"
                + "function errorSummary(error){return {name:error&&error.name?String(error.name):'Error',"
                + "message:error&&error.message?String(error.message).slice(0,160):''};}"
                + "function snapshot(details){var data={elapsedMs:Date.now()-startedAt,readyState:document.readyState,"
                + "visibilityState:document.visibilityState,hidden:document.hidden,hasFocus:document.hasFocus()};"
                + "if(details){Object.keys(details).forEach(function(key){data[key]=details[key];});}return data;}"
                + "function log(event,details){console.info(PREFIX+' '+event+' '+JSON.stringify(snapshot(details)));}"
                + "function lifecycle(event){if(event.type==='pagehide'||event.type==='beforeunload'||document.hidden){handoffObserved=true;}"
                + "log(event.type,{persisted:event.persisted===true});}"
                + "document.addEventListener('visibilitychange',function(event){lifecycle(event);});"
                + "window.addEventListener('pagehide',lifecycle);window.addEventListener('pageshow',lifecycle);"
                + "window.addEventListener('blur',lifecycle);window.addEventListener('focus',lifecycle);"
                + "window.addEventListener('beforeunload',lifecycle);"
                + "window.addEventListener('error',function(event){log('js_error',{line:event.lineno||0,column:event.colno||0});});"
                + "window.addEventListener('unhandledrejection',function(event){var reason=event.reason;"
                + "log('unhandledrejection',{reasonType:typeof reason,reasonName:reason&&reason.name?String(reason.name):''});});"
                + "function bridgeAvailable(){return !!(window.uni&&uni.webView&&uni.webView.getEnv&&uni.webView.redirectTo);}"
                + "function schemeFallback(reason){if(handoffObserved||schemeStarted){return;}schemeStarted=true;"
                + "log('scheme_fallback_start',{reason:reason,target:targetSummary(target),orderRef:orderRef(target)});"
                + "try{window.location.replace(target);}catch(error){log('scheme_fallback_exception',errorSummary(error));}}"
                + "function iosParentRedirect(trigger){if(!/iPhone|iPad|iPod/i.test(navigator.userAgent)||!window.plus||!plus.webview){return false;}"
                + "try{var current=plus.webview.currentWebview(),parent=current&&current.parent?current.parent():null;"
                + "log('ios_parent_redirect_environment',{trigger:trigger,current:!!current,parent:!!parent});"
                + "if(!parent||typeof parent.evalJS!=='function'){return false;}"
                + "log('ios_parent_redirect_start',{trigger:trigger,routePath:routePath(appRoute),orderRef:orderRef(target)});"
                + "parent.evalJS('uni.redirectTo({url:'+JSON.stringify(appRoute)+'})');"
                + "setTimeout(function(){if(!handoffObserved){schemeFallback('ios_parent_no_handoff');}},1200);return true;}"
                + "catch(error){log('ios_parent_redirect_exception',errorSummary(error));return false;}}"
                + "function bridgeRedirect(trigger,force){if(handoffObserved||(bridgeStarted&&!force)||!bridgeAvailable()){return false;}"
                + "bridgeStarted=true;var envResolved=false;var envTimer=setTimeout(function(){if(!envResolved){"
                + "log('bridge_environment_timeout',{trigger:trigger});schemeFallback('bridge_environment_timeout');}},500);"
                + "try{uni.webView.getEnv(function(env){envResolved=true;clearTimeout(envTimer);env=env||{};"
                + "log('bridge_environment',{trigger:trigger,plus:env.plus===true,nvue:env.nvue===true,uvue:env.uvue===true,h5:env.h5===true});"
                + "if(!(env.plus||env.nvue||env.uvue)){schemeFallback('bridge_not_app');return;}"
                + "log('bridge_redirect_start',{trigger:trigger,routePath:routePath(appRoute),orderRef:orderRef(target)});"
                + "if(env.plus&&iosParentRedirect(trigger)){return;}"
                + "try{uni.webView.redirectTo({url:appRoute});setTimeout(function(){if(!handoffObserved){"
                + "schemeFallback('bridge_no_handoff');}},1200);}catch(error){log('bridge_redirect_exception',"
                + "errorSummary(error));schemeFallback('bridge_exception');}});}"
                + "catch(error){envResolved=true;clearTimeout(envTimer);log('bridge_environment_exception',"
                + "errorSummary(error));schemeFallback('bridge_environment_exception');}return true;}"
                + "link.addEventListener('touchstart',function(event){log('manual_open_touch',{isTrusted:event.isTrusted===true,"
                + "target:targetSummary(target),orderRef:orderRef(target)});},{passive:true});"
                + "link.addEventListener('click',function(event){log('manual_open_click',{isTrusted:event.isTrusted===true,"
                + "target:targetSummary(target),orderRef:orderRef(target)});if(bridgeAvailable()){event.preventDefault();"
                + "schemeStarted=false;bridgeRedirect('manual',true);}});"
                + "document.addEventListener('UniAppJSBridgeReady',function(){log('bridge_ready',{});bridgeRedirect('ready',false);});"
                + "log('page_loaded',{userAgent:navigator.userAgent,platform:navigator.platform||'',language:navigator.language||'',"
                + "page:{origin:window.location.origin,pathname:window.location.pathname},target:targetSummary(target),orderRef:orderRef(target)});"
                + "[250,1000,3000].forEach(function(delay){setTimeout(function(){log('auto_open_observation',{delayMs:delay,"
                + "stillVisible:!document.hidden,target:targetSummary(target),orderRef:orderRef(target)});},delay);});"
                + "log('auto_open_start',{target:targetSummary(target),routePath:routePath(appRoute),orderRef:orderRef(target)});"
                + "if(window.UniAppJSBridge){setTimeout(function(){bridgeRedirect('already_ready',false);},0);}"
                + "setTimeout(function(){if(!bridgeStarted){schemeFallback('bridge_ready_timeout');}},1000);"
                + "})();</script>";
    }

    private static String encode(String value) {
        return URLEncoder.encode(value == null ? "" : value, StandardCharsets.UTF_8)
                .replace("+", "%20");
    }

    private static String escapeHtml(String value) {
        if (value == null) {
            return "";
        }
        return value.replace("&", "&amp;").replace("<", "&lt;")
                .replace(">", "&gt;").replace("\"", "&quot;").replace("'", "&#39;");
    }
}
