<?php

namespace App\Http\Controllers;

use App\Models\IntegrationSetting;
use App\Models\IntegrationSyncLog;
use App\Models\IntegrationFieldMapping;
use App\Models\Ticket;
use App\Services\CrmIntegrationService;
use App\Services\IntegrationOperationService;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Throwable;

class IntegrationController extends Controller
{
    private const PROVIDERS = ['facebook', 'whatsapp', 'mailchimp', 'jira', 'google_calendar', 'outlook_calendar'];

    public function __construct()
    {
        $this->middleware(['auth', 'verified', 'business.complete']);
    }

    public function index(Request $request)
    {
        $this->useDefaultDateRange($request);
        $request->validate(['q'=>['nullable','string','max:100'],'date_from'=>['nullable','date'],'date_to'=>['nullable','date','after_or_equal:date_from']]);
        $search=trim((string)$request->input('q'));
        $settings = IntegrationSetting::where('business_id', auth()->user()->business_id)
            ->get()->keyBy('provider');
        $tickets = Ticket::where('business_id', auth()->user()->business_id)
            ->latest()->limit(100)->get();
        $logs = IntegrationSyncLog::where('business_id', auth()->user()->business_id)
            ->when($request->filled('date_from'), fn ($query) => $query->whereDate('created_at','>=',$request->date_from))
            ->when($request->filled('date_to'), fn ($query) => $query->whereDate('created_at','<=',$request->date_to))
            ->when($search!=='',fn($query)=>$query->where(fn($filter)=>$filter
                ->where('provider','like',"%{$search}%")->orWhere('operation','like',"%{$search}%")
                ->orWhere('status','like',"%{$search}%")->orWhere('external_id','like',"%{$search}%")
                ->orWhere('error','like',"%{$search}%")))
            ->latest()->paginate(30, ['*'], 'sync_page')->withQueryString();
        $mappings = IntegrationFieldMapping::where('business_id', auth()->user()->business_id)
            ->orderBy('provider')->orderBy('entity_type')->get();
        $required = [
            'facebook'=>[['credentials','access_token'],['configuration','page_id'],['configuration','lead_form_id']],
            'whatsapp'=>[['credentials','access_token'],['configuration','phone_number_id']],
            'mailchimp'=>[['credentials','api_key'],['configuration','server_prefix'],['configuration','audience_id']],
            'jira'=>[['credentials','email'],['credentials','api_token'],['configuration','site_url'],['configuration','project_key']],
            'google_calendar'=>[['credentials','access_token'],['configuration','calendar_id']],
            'outlook_calendar'=>[['credentials','access_token'],['configuration','calendar_id']],
        ];
        $readiness = collect($required)->map(function($fields,$provider) use($settings){
            $setting=$settings->get($provider);$missing=collect($fields)->filter(fn($field)=>blank(data_get($setting?->{$field[0]}??[],$field[1])))
                ->map(fn($field)=>$field[1])->values();
            $providerLogs=IntegrationSyncLog::where('business_id',auth()->user()->business_id)->where('provider',$provider);
            return ['configured'=>$setting?->enabled&&$missing->isEmpty(),'missing'=>$missing,
                'healthy'=>$setting?->health_status==='healthy','expired'=>$setting?->credentials_expires_at?->isPast()??false,
                'last_success'=>(clone $providerLogs)->where('status','completed')->latest()->value('completed_at'),
                'last_inbound'=>(clone $providerLogs)->where('direction','inbound')->latest()->value('created_at'),
                'failed'=>(clone $providerLogs)->where('status','failed')->count()];
        });

        return view('settings.integrations', compact('settings', 'tickets', 'logs', 'mappings','readiness'));
    }

    public function update(Request $request, string $provider)
    {
        $this->ensureAdmin();
        abort_unless(in_array($provider, self::PROVIDERS, true), 404);

        $request->validate([
            'enabled' => 'nullable|boolean',
            'credentials' => 'nullable|array',
            'credentials.*' => 'nullable|string|max:2048',
            'configuration' => 'nullable|array',
            'configuration.*' => 'nullable|string|max:2048',
            'credentials_expires_at' => 'nullable|date',
        ]);

        $setting = IntegrationSetting::firstOrNew([
            'business_id' => auth()->user()->business_id,
            'provider' => $provider,
        ]);

        $credentials = $setting->credentials ?? [];
        foreach ($request->input('credentials', []) as $key => $value) {
            if ($value !== null && $value !== '') {
                $credentials[$key] = $value;
            }
        }

        $setting->fill([
            'credentials' => $credentials,
            'configuration' => array_filter(
                $request->input('configuration', []),
                fn ($value) => $value !== null && $value !== ''
            ),
            'enabled' => $request->boolean('enabled'),
            'last_error' => null,
            'credentials_expires_at' => $request->input('credentials_expires_at'),
        ])->save();

        return back()->with('success', ucfirst($provider).' integration settings saved.');
    }

    public function test(string $provider, CrmIntegrationService $service)
    {
        $this->ensureAdmin();
        return $this->perform($provider, 'health_check', [], function () use ($service, $provider) {
            if (in_array($provider, ['google_calendar', 'outlook_calendar'], true)) {
                app(\App\Services\CalendarSyncService::class)->health($this->settingFor($provider));
            } else {
                $service->test($provider);
            }
            IntegrationSetting::where('business_id',auth()->user()->business_id)->where('provider',$provider)
                ->update(['health_status'=>'healthy','last_health_checked_at'=>now(),'last_error'=>null]);
            return ucfirst($provider).' connection successful.';
        });
    }

    private function settingFor(string $provider): IntegrationSetting
    {
        return IntegrationSetting::where('business_id', auth()->user()->business_id)
            ->where('provider', $provider)->where('enabled', true)->firstOrFail();
    }

    public function syncFacebook(CrmIntegrationService $service)
    {
        return $this->perform('facebook', 'facebook_import', [], fn () =>
            $service->importFacebookLeads().' new Facebook lead(s) imported.'
        );
    }

    public function syncMailchimp(CrmIntegrationService $service)
    {
        return $this->perform('mailchimp', 'mailchimp_contacts', [], fn () =>
            $service->syncMailchimpContacts().' CRM contact(s) synchronized to Mailchimp.'
        );
    }

    public function sendWhatsApp(Request $request, CrmIntegrationService $service)
    {
        $validated = $request->validate([
            'recipient' => ['required', 'string', 'max:30', 'regex:/^\+?[0-9 ()-]+$/'],
            'message' => 'required|string|max:4096',
        ]);

        return $this->perform('whatsapp', 'whatsapp_send', $validated, function () use ($service, $validated) {
            $service->sendWhatsApp($validated['recipient'], $validated['message']);
            return 'WhatsApp message sent successfully.';
        });
    }

    public function createJiraIssue(Request $request, CrmIntegrationService $service)
    {
        $validated = $request->validate([
            'ticket_id' => [
                'required',
                Rule::exists('tickets', 'id')->where(
                    fn ($query) => $query->where('business_id', auth()->user()->business_id)
                ),
            ],
        ]);

        return $this->perform('jira', 'jira_issue', $validated, function () use ($service, $validated) {
            $key = $service->createJiraIssue(Ticket::findOrFail($validated['ticket_id']));
            return "Jira issue {$key} created successfully.";
        });
    }

    public function mappings(Request $request)
    {
        $this->ensureAdmin();
        $data=$request->validate([
            'provider'=>'required|in:facebook,whatsapp,mailchimp,jira',
            'entity_type'=>'required|in:lead,contact,message,ticket',
            'external_field'=>'required|string|max:255','crm_field'=>'required|string|max:255',
            'value_map'=>'nullable|json','enabled'=>'nullable|boolean',
        ]);
        IntegrationFieldMapping::updateOrCreate([
            'business_id'=>$request->user()->business_id,'provider'=>$data['provider'],
            'entity_type'=>$data['entity_type'],'external_field'=>$data['external_field'],
        ], ['crm_field'=>$data['crm_field'],'value_map'=>filled($data['value_map']??null)?json_decode($data['value_map'],true):null,
            'enabled'=>$request->boolean('enabled',true)]);
        return back()->with('success','Integration field mapping saved.');
    }

    public function destroyMapping(IntegrationFieldMapping $mapping)
    {
        $this->ensureAdmin();
        abort_unless($mapping->business_id===auth()->user()->business_id,403);
        $mapping->delete();
        return back()->with('success','Field mapping removed.');
    }

    public function retry(IntegrationSyncLog $log, IntegrationOperationService $operations)
    {
        $this->ensureAdmin();
        abort_unless($log->business_id===auth()->user()->business_id && $log->direction==='outbound',403);
        $log->update(['status'=>'pending','attempts'=>0,'next_retry_at'=>now(),'error'=>null]);
        $operations->process($log);
        return back()->with('success','Synchronization operation retried.');
    }

    private function perform(string $provider, string $operation, array $payload, callable $action)
    {
        $log=IntegrationSyncLog::create([
            'business_id'=>auth()->user()->business_id,'provider'=>$provider,'direction'=>'outbound',
            'operation'=>$operation,'status'=>'processing','payload'=>$payload,'attempts'=>1,
        ]);
        try {
            $message=$action();
            $log->update(['status'=>'completed','completed_at'=>now(),'error'=>null]);
            return back()->with('success', $message);
        } catch (Throwable $exception) {
            $log->update(['status'=>'pending','error'=>$exception->getMessage(),'next_retry_at'=>now()->addMinute()]);
            IntegrationSetting::where('business_id', auth()->user()->business_id)
                ->where('provider', $provider)
                ->update(['last_error' => $exception->getMessage(),'health_status'=>'degraded']);

            report($exception);
            return back()->withErrors([
                'integration' => ucfirst($provider).' error: '.$exception->getMessage(),
            ]);
        }
    }

    private function ensureAdmin(): void
    {
        abort_unless((int) auth()->user()->is_admin === 1, 403);
    }
}
