<?php

namespace App\Services;

use App\Models\IntegrationSetting;
use App\Models\IntegrationSyncLog;
use App\Models\Ticket;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use RuntimeException;

class IntegrationOperationService
{
    public function process(IntegrationSyncLog $log): void
    {
        if ($log->direction !== 'outbound' || $log->attempts >= $log->max_attempts) return;
        $user = User::withoutGlobalScopes()->where('business_id',$log->business_id)
            ->orderByDesc('is_admin')->first();
        if (!$user) {
            $log->update(['status'=>'failed','error'=>'No business user is available to execute integration operations.']);
            return;
        }

        Auth::login($user);
        $log->update(['status'=>'processing','attempts'=>$log->attempts+1,'next_retry_at'=>null]);
        try {
            $service=app(CrmIntegrationService::class);
            $payload=$log->payload??[];
            match($log->operation) {
                'facebook_import' => $service->importFacebookLeads(),
                'mailchimp_contacts' => $service->syncMailchimpContacts(),
                'whatsapp_send' => $service->sendWhatsApp($payload['recipient'],$payload['message']),
                'jira_issue' => $service->createJiraIssue(Ticket::withoutGlobalScopes()
                    ->where('business_id',$log->business_id)->findOrFail($payload['ticket_id'])),
                'health_check' => $service->test($log->provider),
                default => throw new RuntimeException('Unsupported retry operation: '.$log->operation),
            };
            $log->update(['status'=>'completed','completed_at'=>now(),'error'=>null]);
        } catch (\Throwable $exception) {
            $attempts=$log->attempts;
            $final=$attempts >= $log->max_attempts;
            $log->update([
                'status'=>$final?'failed':'pending','error'=>$exception->getMessage(),
                'next_retry_at'=>$final?null:now()->addMinutes(min(60,2 ** max(0,$attempts-1))),
            ]);
            IntegrationSetting::withoutGlobalScopes()->where([
                'business_id'=>$log->business_id,'provider'=>$log->provider,
            ])->update(['health_status'=>'degraded','last_error'=>$exception->getMessage()]);
            report($exception);
        } finally {
            Auth::logout();
        }
    }

    public function health(IntegrationSetting $setting): void
    {
        $user=User::withoutGlobalScopes()->where('business_id',$setting->business_id)
            ->orderByDesc('is_admin')->first();
        if(!$user)return;
        Auth::login($user);
        try {
            if($setting->credentials_expires_at && $setting->credentials_expires_at->lte(now()->addMinutes(10))){
                $this->refreshCredentials($setting);
            }
            app(CrmIntegrationService::class)->test($setting->provider);
            $setting->update(['health_status'=>'healthy','last_health_checked_at'=>now(),'last_error'=>null,'refresh_error'=>null]);
        } catch(\Throwable $exception) {
            $setting->update(['health_status'=>$setting->credentials_expires_at?->isPast()?'expired':'unhealthy',
                'last_health_checked_at'=>now(),'last_error'=>$exception->getMessage()]);
        } finally {Auth::logout();}
    }

    private function refreshCredentials(IntegrationSetting $setting): void
    {
        $credentials=$setting->credentials??[];$configuration=$setting->configuration??[];
        if(empty($configuration['oauth_token_url']) || empty($credentials['refresh_token'])){
            throw new RuntimeException('Credentials are expired and no OAuth refresh configuration is available.');
        }
        try{
            $data=Http::asForm()->post($configuration['oauth_token_url'],[
                'grant_type'=>'refresh_token','refresh_token'=>$credentials['refresh_token'],
                'client_id'=>$credentials['client_id']??null,'client_secret'=>$credentials['client_secret']??null,
            ])->throw()->json();
            $credentials['access_token']=$data['access_token'];
            if(!empty($data['refresh_token']))$credentials['refresh_token']=$data['refresh_token'];
            $setting->update(['credentials'=>$credentials,'credentials_expires_at'=>now()->addSeconds((int)($data['expires_in']??3600)),
                'last_refreshed_at'=>now(),'refresh_error'=>null]);
        }catch(\Throwable $exception){
            $setting->update(['refresh_error'=>$exception->getMessage()]);
            throw $exception;
        }
    }
}
