<?php

namespace App\Services;

use App\Models\SmsGateway;
use App\Models\GeneralSetting;
use App\Models\Customer;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;

class SmsService
{
    /**
     * Send SMS via MimSMS. Falls back to email if gateway is off or fails.
     *
     * @param string $to  Phone number or email address
     * @param string $message
     * @param string $name  Recipient name for email greeting
     * @param string|null $otp  OTP value (used in email subject)
     * @return bool
     */
    public function sendSms(string $to, string $message, string $name = 'Customer', ?string $otp = null): bool
    {
        $gateway = SmsGateway::first();
        $smsActive = $gateway && (int)$gateway->status === 1;

        // 1. Try SMS if gateway is active
        if ($smsActive) {
            $result = $this->sendViaMimSms($gateway, $to, $message);
            if ($result) {
                return true;
            }
            Log::warning("MimSMS failed for {$to}, attempting email fallback.");
        }

        // 2. Fallback: email if email_otp is enabled OR gateway is off
        $emailOtpEnabled = $gateway && (int)($gateway->email_otp ?? 0) === 1;
        if (!$smsActive || $emailOtpEnabled) {
            return $this->sendViaEmail($to, $message, $name, $otp);
        }

        return false;
    }

    /**
     * Send via MimSMS API (https://www.mimsms.com/api-documentation)
     */
    protected function sendViaMimSms(SmsGateway $gateway, string $to, string $message): bool
    {
        try {
            $url = rtrim($gateway->url ?? 'https://api.mimsms.com/api/SmsSending/SMS', '/');

            $response = Http::timeout(15)->post($url, [
                'UserName'        => $gateway->username,
                'Apikey'          => $gateway->api_key,
                'MobileNumber'    => $this->formatNumber($to),
                'CampaignId'      => 'null',
                'SenderName'      => $gateway->serderid ?? 'MiMSMS',
                'TransactionType' => 'T',
                'Message'         => $message,
            ]);

            $result = $response->json();

            if (isset($result['statusCode']) && (string)$result['statusCode'] === '200') {
                Log::info("MimSMS sent to {$to}: " . json_encode($result));
                return true;
            }

            Log::error("MimSMS failed for {$to}: " . json_encode($result));
            return false;
        } catch (\Exception $e) {
            Log::error("MimSMS exception for {$to}: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Send OTP / notification via email fallback.
     * If $to is a phone number, looks up the customer's email.
     */
    protected function sendViaEmail(string $to, string $message, string $name, ?string $otp): bool
    {
        $email = $to;

        if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
            $customer = Customer::where('phone', $to)->first();
            $email = $customer?->email ?? null;
        }

        if (!$email) {
            Log::warning("Email fallback: no email found for identifier: {$to}");
            return false;
        }

        try {
            $this->reloadMailConfig();

            $site         = GeneralSetting::where('status', 1)->first();
            $siteName     = $site->name ?? config('app.name');
            $primaryColor = $site->primary_color ?? '#E31019';
            $logo         = $site->logo ? config('app.url') . '/' . ltrim($site->logo, '/') : null;

            $subject = $otp
                ? "Your OTP Code: {$otp} — {$siteName}"
                : "Notification — {$siteName}";

            $viewData = [
                'otp'          => $otp ?? '',
                'name'         => $name,
                'message'      => $message,
                'siteName'     => $siteName,
                'primaryColor' => $primaryColor,
                'logo'         => $logo,
            ];

            $view = $otp ? 'emails.otp' : null;

            if ($view) {
                Mail::send($view, $viewData, function ($msg) use ($email, $subject) {
                    $msg->to($email)->subject($subject);
                });
            } else {
                $htmlBody = nl2br(e($message));
                Mail::send([], [], function ($msg) use ($email, $subject, $htmlBody) {
                    $msg->to($email)->subject($subject)
                        ->html("<p style='font-family:sans-serif;font-size:15px;'>{$htmlBody}</p>");
                });
            }

            Log::info("Email sent to {$email}");
            return true;
        } catch (\Exception $e) {
            Log::error("Email fallback failed for {$email}: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Re-apply mail config from current .env values so runtime .env changes take effect.
     */
    protected function reloadMailConfig(): void
    {
        $config = [
            'transport'  => env('MAIL_MAILER', 'smtp'),
            'host'       => env('MAIL_HOST', 'smtp.mailgun.org'),
            'port'       => (int) env('MAIL_PORT', 587),
            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
            'username'   => env('MAIL_USERNAME'),
            'password'   => env('MAIL_PASSWORD'),
            'timeout'    => null,
        ];

        config(['mail.mailers.smtp' => $config]);
        config(['mail.from.address' => env('MAIL_FROM_ADDRESS', 'hello@example.com')]);
        config(['mail.from.name'    => env('MAIL_FROM_NAME', config('app.name'))]);

        // Properly purge the Laravel mail manager so it rebuilds with new config
        $mailer = app('mail.manager');
        if (method_exists($mailer, 'forgetMailers')) {
            $mailer->forgetMailers();
        } else {
            // Fallback: reset the resolved mailers array via reflection
            try {
                $ref = new \ReflectionProperty($mailer, 'mailers');
                $ref->setAccessible(true);
                $ref->setValue($mailer, []);
            } catch (\Throwable $e) {
                // ignore
            }
        }
    }

    /**
     * Format BD number to 8801XXXXXXXXX
     */
    protected function formatNumber(string $number): string
    {
        $number = preg_replace('/[^0-9]/', '', $number);
        if (strlen($number) === 11 && str_starts_with($number, '01')) {
            $number = '88' . $number;
        }
        return $number;
    }

    /**
     * Check if SMS gateway is currently active
     */
    public function isSmsActive(): bool
    {
        $gateway = SmsGateway::first();
        return $gateway && (int)$gateway->status === 1;
    }

    /**
     * Check if email OTP fallback is enabled
     */
    public function isEmailOtpEnabled(): bool
    {
        $gateway = SmsGateway::first();
        return $gateway && (int)($gateway->email_otp ?? 0) === 1;
    }

    /**
     * Send OTP/notification directly to an email address (no SMS).
     */
    public function sendEmailToAddress(string $email, string $name, string $message, ?string $otp = null, ?string $subject = null): bool
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return false;
        }

        try {
            $this->reloadMailConfig();
            $site = GeneralSetting::where('status', 1)->first();
            $siteName = $site->name ?? config('app.name');
            $primaryColor = $site->primary_color ?? '#E31019';
            $logo = $site->logo ? config('app.url') . '/' . ltrim($site->logo, '/') : null;

            $mailSubject = $subject ?? ($otp ? "Your OTP Code: {$otp} — {$siteName}" : "Notification — {$siteName}");

            if ($otp) {
                Mail::send('emails.otp', [
                    'otp' => $otp,
                    'name' => $name,
                    'message' => $message,
                    'siteName' => $siteName,
                    'primaryColor' => $primaryColor,
                    'logo' => $logo,
                ], function ($msg) use ($email, $mailSubject) {
                    $msg->to($email)->subject($mailSubject);
                });
            } else {
                $htmlBody = nl2br(e($message));
                Mail::send([], [], function ($msg) use ($email, $mailSubject, $htmlBody) {
                    $msg->to($email)->subject($mailSubject)
                        ->html("<p style='font-family:sans-serif;font-size:15px;'>{$htmlBody}</p>");
                });
            }

            return true;
        } catch (\Exception $e) {
            Log::error("Direct email failed for {$email}: " . $e->getMessage());
            return false;
        }
    }
}
