<?php
namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\RequestException;
use Closure;
use App\Http\Responses\ApiResponse;

class ApiClient
{
    protected string $baseUrl;
    protected string $token;

    protected int $timeout = 10;
    protected int $connectTimeout = 5;
    protected int $retryTimes = 0;
    protected int $retryDelay = 100;

    protected ?Closure $fallbackHandler = null;
    protected bool $enableLogging = true;

    public function __construct(string $baseUrl = '', string $token = '')
    {
        $this->baseUrl = rtrim($baseUrl, '/');
        $this->token = $token;
    }

    public function setBaseUrl(string $url): self
    {
        $this->baseUrl = rtrim($url, '/');
        return $this;
    }

    public function setToken(string $token): self
    {
        $this->token = $token;
        return $this;
    }

    public function setTimeout(int $seconds): self
    {
        $this->timeout = $seconds;
        return $this;
    }

    public function setConnectTimeout(int $seconds): self
    {
        $this->connectTimeout = $seconds;
        return $this;
    }

    public function setRetry(int $times, int $delayMs = 100): self
    {
        $this->retryTimes = $times;
        $this->retryDelay = $delayMs;
        return $this;
    }

    public function setFallbackHandler(?Closure $handler): self
    {
        $this->fallbackHandler = $handler;
        return $this;
    }

    public function enableLogging(bool $value = true): self
    {
        $this->enableLogging = $value;
        return $this;
    }

    protected function withDefaultHeaders(): PendingRequest
    {
        $request = Http::connectTimeout($this->connectTimeout)
            ->timeout($this->timeout)
            ->withHeaders([
                'Accept'        => 'application/json',
                'Authorization' => 'Bearer ' . $this->token,
            ]);

        if ($this->retryTimes > 0) {
            $request = $request->retry($this->retryTimes, $this->retryDelay, function ($exception, $request) {
                if ($this->enableLogging) {
                    Log::warning('API retrying...', [
                        'url' => $request->url(),
                        'exception' => $exception->getMessage(),
                    ]);
                }
                return true;
            });
        }

        return $request;
    }

    public function requestWithCatch(callable $fn)
{
    try {
        return $fn();
    } catch (RequestException $e) {
        if ($this->enableLogging) {
            Log::error('API Request Failed', [
                'message' => $e->getMessage(),
                'url'     => $e->request?->url(),
                'code'    => $e->getCode(),
            ]);
        }

        if ($this->fallbackHandler instanceof \Closure) {
            return call_user_func($this->fallbackHandler, $e);
        }

        // 智能 fallback，直接寫在這裡
        $status = $e->response?->status();

        if ($status >= 500) {
            return ApiResponse::error('伺服器錯誤，請稍後再試','SERVER_ERROR',503);
        }

        if ($status === 404) {
            return ApiResponse::error('遠端 API 路徑不存在','API_NOT_FOUND',404);
        }

        if ($status === 401 || $status === 403) {
            return ApiResponse::unauthorized();
        }

        if ($e->getCode() === 0) {
            return ApiResponse::error('無法連線遠端 API（可能超時或 DNS 錯誤）','CONNECTION_ERROR',504);
        }

        return ApiResponse::error('API 請求失敗: ' . $e->getMessage(), 'HTTP_CLIENT_ERROR',$status ?? 400);
    }
}

    public function get(string $endpoint, array $query = [])
    {
        return $this->requestWithCatch(fn () =>
            $this->withDefaultHeaders()->get("{$this->baseUrl}{$endpoint}", $query)
        );
    }

    public function post(string $endpoint, array $data = [])
    {
        return $this->requestWithCatch(fn () =>
            $this->withDefaultHeaders()->post("{$this->baseUrl}{$endpoint}", $data)
        );
    }

    public function put(string $endpoint, array $data = [])
    {
        return $this->requestWithCatch(fn () =>
            $this->withDefaultHeaders()->put("{$this->baseUrl}{$endpoint}", $data)
        );
    }

    public function patch(string $endpoint, array $data = [])
    {
        return $this->requestWithCatch(fn () =>
            $this->withDefaultHeaders()->patch("{$this->baseUrl}{$endpoint}", $data)
        );
    }

    public function delete(string $endpoint, array $data = [])
    {
        return $this->requestWithCatch(fn () =>
            $this->withDefaultHeaders()->delete("{$this->baseUrl}{$endpoint}", $data)
        );
    }

    public function upload(string $endpoint, array $files = [], array $data = [])
    {
        $this->setTimeout(300);
        $this->setConnectTimeout(10);
        return $this->requestWithCatch(function () use ($endpoint, $files, $data) {
            $request = $this->withDefaultHeaders();

            foreach ($files as $key => $filePath) {
                $filename = basename($filePath);
                $request = $request->attach($key, fopen($filePath, 'r'), $filename);
            }

            return $request->withoutVerifying()->post("{$this->baseUrl}{$endpoint}", $data);
        });
    }
}