<?php

namespace App\Http\Middleware;

use App\Traits\CacheObject;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Mtc\MercuryDataModels\SeoRedirect;

class SeoRedirectCheckMiddleware
{
    use CacheObject;

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        if (($redirect = $this->checkRedirect($request)) !== null) {
            if ((int) $redirect->code === 410) {
                return response([
                    'type' => 'gone',
                    'code' => 410,
                ], 410);
            }
            return response([
                'type' => 'redirect',
                'to' => $redirect->toValue(),
                'code' => $redirect->code
            ], 404);
        }
        return $next($request);
    }

    /**
     * @param Request $request
     * @return Model|SeoRedirect|null
     */
    private function checkRedirect(Request $request): ?SeoRedirect
    {
        $xPath = $request->header('x-path');
        if (stripos($xPath, '?')) {
            $parts = explode('?', $xPath);
            $xPath = $parts[0];
        }
        $domain = str_replace('www.', '', $request->header('x-tenant'));

        $redirect = $this->cache('redirects-' . $xPath, 60, function () use ($xPath, $domain) {
            $redirect = SeoRedirect::query()
                ->where('from', $xPath)
                ->first();

            if (!$redirect) {
                $redirect = SeoRedirect::query()
                    ->where('from_domain', 'like', '%' . $domain)
                    ->where('from', '*')
                    ->first();
            }

            if (!$redirect) {
                $regexRedirects = SeoRedirect::query()
                    ->where('has_regex', 1)
                    ->get();
                foreach ($regexRedirects as $regexRedirect) {
                    if (preg_match('#' . $regexRedirect->from . '#', $xPath)) {
                        $newUrl = preg_replace(
                            '#' . $regexRedirect->from . '#',
                            (string) $regexRedirect->to,
                            $xPath
                        );
                        $redirect = $regexRedirect;
                        $redirect->to = $newUrl;
                        break;
                    }
                }
            }

            return $redirect;
        }, 'seo-redirects');

        if ($redirect && !empty($redirect->from_domain)) {
            $domainMatches = $domain == str_replace('www.', '', $redirect->from_domain);
            if (!$domainMatches) {
                return null;
            }
        }

        return $redirect;
    }
}
