<?php

namespace App\Exceptions;

use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * 슬랙 알림에서 무시할 예외인지 확인
     */
    protected function shouldIgnoreException(Throwable $e): bool
    {
        // 세션 만료로 인한 인증 실패는 슬랙 알림 제외 (API Key 검증 통과 후 발생하므로 정상 케이스)
        if ($e instanceof AuthenticationException && $e->getMessage() === '회원정보 정보 없음') {
            return true;
        }

        return false;
    }

    public function report(Throwable $e): void
    {
        // 무시할 예외인 경우 슬랙/로그 모두 건너뜀
        if ($this->shouldIgnoreException($e)) {
            return;
        }

        try {
            if (
                app()->environment('local') || app()->environment('production')
                || app()->environment('LOCAL') || app()->environment('DEV')
            ) {
                $this->sendSlackException($e);
            }
        } catch (\Throwable $ex) {
            // app()이 아직 사용 불가하거나 env 문제가 있을 때는 무시
        }

        parent::report($e); // 로그는 그대로
    }

    protected function sendSlackException(Throwable $e): void
    {
        try {
            $url = env('LOG_SLACK_WEBHOOK_URL');

            if (! $url) {
                return;
            }

            $ip = request()?->ip() ?? 'N/A'; // 요청이 없는 경우 대비

            Http::post($url, [
                'text' => "*[Laravel] 예외 발생!*\n".
                    "• 메시지: `{$e->getMessage()}`\n".
                    "• 위치: `{$e->getFile()}:{$e->getLine()}`\n".
                    '• 시간: '.now()->toDateTimeString()."\n".
                    "• IP: `{$ip}`",
            ]);
        } catch (Throwable $ex) {
            logger()->error('슬랙 전송 실패', ['message' => $ex->getMessage()]);
        }
    }

    public function render($request, Throwable $exception)
    {
        // API 라우트는 무조건 JSON 응답 (Accept 헤더 없어도)
        $isApiRoute = str_starts_with($request->path(), 'api/');

        if ($request->expectsJson() || $isApiRoute) {
            // 422 Unprocessable Entity - Validation 실패
            if ($exception instanceof ValidationException) {
                return response()->json([
                    'success' => false,
                    'message' => '입력값 검증 실패',
                    'error' => [
                        'code' => 422,
                        'details' => $exception->errors(),
                    ],
                ], 422);
            }

            // 400 Bad Request
            if ($exception instanceof BadRequestHttpException) {
                return response()->json([
                    'success' => false,
                    'message' => '잘못된 요청',
                    'data' => null,
                ], 400);
            }

            // 401 Unauthorized
            if ($exception instanceof AuthenticationException) {
                // 토큰 만료 여부 확인
                $errorCode = null;
                $message = '인증 실패';

                // Bearer 토큰이 있는 경우 만료 여부 확인
                $bearerToken = $request->bearerToken();
                if ($bearerToken) {
                    $token = \Laravel\Sanctum\PersonalAccessToken::findToken($bearerToken);
                    if ($token && $token->expires_at && $token->expires_at->isPast()) {
                        $errorCode = 'TOKEN_EXPIRED';
                        $message = __('error.token_expired');
                    }
                }

                return response()->json([
                    'success' => false,
                    'message' => $message,
                    'error_code' => $errorCode,
                    'data' => null,
                ], 401);
            }

            // 403 Forbidden
            if ($exception instanceof AccessDeniedHttpException) {
                return response()->json([
                    'success' => false,
                    'message' => '권한 없음',
                    'data' => null,
                ], 403);
            }

            // 404 Not Found - 라우트 없음
            if ($exception instanceof NotFoundHttpException) {
                return response()->json([
                    'success' => false,
                    'message' => '존재하지 않는 URI 또는 데이터',
                    'data' => null,
                ], 404);
            }

            // 404 Not Found - 모델 없음 (findOrFail 등)
            if ($exception instanceof ModelNotFoundException) {
                return response()->json([
                    'success' => false,
                    'message' => '데이터를 찾을 수 없습니다',
                    'data' => null,
                ], 404);
            }

            // 405 Method Not Allowed
            if ($exception instanceof MethodNotAllowedHttpException) {
                return response()->json([
                    'success' => false,
                    'message' => '허용되지 않는 메서드',
                    'data' => null,
                ], 405);
            }

            // 400 Bad Request - 품목 코드 중복
            if ($exception instanceof DuplicateCodeException) {
                return response()->json([
                    'success' => false,
                    'message' => $exception->getMessage(),
                    'error' => [
                        'code' => 400,
                    ],
                    'duplicate_id' => $exception->getDuplicateId(),
                    'duplicate_code' => $exception->getDuplicateCode(),
                ], 400);
            }

            // 500 Internal Server Error (기타 모든 에러)
            if (
                $exception instanceof HttpException &&
                $exception->getStatusCode() === 500
            ) {
                return response()->json([
                    'success' => false,
                    'message' => '서버 에러',
                    'data' => null,
                ], 500);
            }

            // 그 외 모든 예외
            return response()->json([
                'success' => false,
                'message' => '서버 에러',
                'data' => null,
            ], 500);
        }

        return parent::render($request, $exception);
    }
}
