package com.zhpb.gdyd_zhpb_zgf.web;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.error.ErrorAttributeOptions.Include;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.ServletWebRequest;

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * 自定义错误控制器：在数据库等常见错误发生时，用中文进行友好提示，避免晦涩的堆栈信息。
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class FriendlyErrorController implements ErrorController {

    private final ErrorAttributes errorAttributes;

    public FriendlyErrorController(ErrorAttributes errorAttributes) {
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
    public ResponseEntity<String> errorHtml(@NonNull HttpServletRequest request) {
        ErrorViewModel model = buildModel(request);
        String html = renderHtml(model);
        return ResponseEntity.status(model.status().value())
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_HTML_VALUE)
                .body(html);
    }

    @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Map<String, Object>> errorJson(@NonNull HttpServletRequest request) {
        ErrorViewModel model = buildModel(request);
        Map<String, Object> body = new HashMap<>();
        body.put("status", model.status().value());
        body.put("error", model.status().getReasonPhrase());
        body.put("message", model.friendlyMessage());
        body.put("timestamp", model.timestamp());
        body.put("path", model.path());
        return ResponseEntity.status(model.status().value()).body(body);
    }

    private ErrorViewModel buildModel(@NonNull HttpServletRequest request) {
        ServletWebRequest webRequest = new ServletWebRequest(request);
        Map<String, Object> attrs = errorAttributes.getErrorAttributes(webRequest,
                ErrorAttributeOptions.defaults().including(Include.MESSAGE));
        Throwable error = errorAttributes.getError(webRequest);

        int statusCode = (int) attrs.getOrDefault("status", 500);
        HttpStatus status = HttpStatus.resolve(statusCode);
        if (status == null) {
            status = HttpStatus.INTERNAL_SERVER_ERROR;
        }
        String path = (String) attrs.getOrDefault("path", request.getRequestURI());

        String rawMessage = extractRawMessage(attrs, error);
        String friendly = translate(rawMessage, status);

        return new ErrorViewModel(status, friendly, path,
                attrs.getOrDefault("timestamp", OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)).toString());
    }

    private String extractRawMessage(Map<String, Object> attrs, Throwable error) {
        StringBuilder sb = new StringBuilder();
        if (attrs.get("error") != null) {
            sb.append(attrs.get("error")).append(" ");
        }
        if (attrs.get("message") != null) {
            sb.append(attrs.get("message")).append(" ");
        }
        if (error != null && error.getMessage() != null) {
            sb.append(error.getMessage());
        }
        return sb.toString();
    }

    private String translate(String origin, HttpStatus status) {
        String lower = origin == null ? "" : origin.toLowerCase(Locale.ROOT);
        if (lower.contains("communications link failure") || lower.contains("connection refused")
                || lower.contains("connect timed out") || lower.contains("could not open jdbc connection")) {
            return "无法连接到数据库，请检查数据库是否启动、账号密码是否正确、网络是否可达。";
        }
        if (lower.contains("password authentication failed") || lower.contains("role") && lower.contains("does not exist")) {
            return "数据库账号或密码错误，请核对配置中的数据库凭证。";
        }
        if (lower.contains("database") && lower.contains("does not exist")) {
            return "数据库不存在，请确认数据库名称是否正确并已创建。";
        }
        if (status.is4xxClientError()) {
            return "请求参数有误或资源不存在，请核对输入后重试。";
        }
        if (status.is5xxServerError()) {
            return "服务内部出现异常，请稍后再试或联系系统管理员。";
        }
        return "系统出现未知错误，请稍后再试。";
    }

    private String renderHtml(ErrorViewModel model) {
        return """
                <!DOCTYPE html>
                <html lang="zh-CN">
                <head>
                    <meta charset="UTF-8">
                    <title>系统提示</title>
                    <style>
                        body {font-family: "Microsoft YaHei", sans-serif; background: #0f172a; color: #e2e8f0; margin:0; padding:0;}
                        .wrapper {max-width: 520px; margin: 10%% auto; background: #1e293b; border-radius: 16px; padding: 32px; text-align: center;
                                  box-shadow: 0 20px 60px rgba(15,23,42,0.4);}
                        h1 {font-size: 26px; margin-bottom: 12px;}
                        p {font-size: 15px; line-height: 1.7;}
                        .status {display:inline-block; padding: 6px 14px; border-radius: 999px; background: rgba(248,113,113,.2);
                                 color: #fecaca; font-weight: 600; margin-bottom: 18px;}
                        .meta {margin-top: 18px; font-size: 13px; color: #94a3b8;}
                        .btn {display:inline-block; margin-top:20px; padding:10px 18px; border-radius:999px;
                              background:#334155; color:#fff; text-decoration:none;}
                    </style>
                </head>
                <body>
                    <div class="wrapper">
                        <div class="status">状态码 %s</div>
                        <h1>系统提示</h1>
                        <p>%s</p>
                        <div class="meta">
                            <div>路径：%s</div>
                            <div>时间：%s</div>
                        </div>
                        <a class="btn" href="/" >返回首页</a>
                    </div>
                </body>
                </html>
                """.formatted(model.status().value(), model.friendlyMessage(), model.path(), model.timestamp());
    }

    private record ErrorViewModel(HttpStatus status, String friendlyMessage, String path, String timestamp) {}
}

