<?php

namespace App\Http\Controllers;

use App\Models\VoiceBroadcast;
use App\Models\VoiceGateway;
use App\Models\Client;
use App\Models\Reseller;
use App\Models\User;
use App\Models\Pop;
use App\Models\CompanyInformation;
use App\Jobs\SendVoiceJob;
use Brian2694\Toastr\Facades\Toastr;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;

class VoiceBroadcastController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:voice_sms_gateway_index', ['only' => ['index', 'create', 'store', 'sendVoice']]);
        $this->middleware('permission:send_batch_voice_sms', ['only' => ['sendVoice']]);
    }

    /**
     * Get active voice gateway credentials
     */
    private function getActiveGateway()
    {
        return VoiceGateway::where('status', 'enable')->first();
    }

    /**
     * Send voice dynamically
     */
    public function sendVoice()
    {
        $reseller = Reseller::resellerList()->get();
        $users = User::whereHas('userdetails', function ($q) {
            $q->where('user_status', 'active');
        })->where('id', '>', 1)
            ->where('email', '!=', 'soiket@outlook.com')
            ->where('email', '!=', 'support@yetfix.com')
            ->where('email', '!=', 'admin@billingfix.xyz')
            ->get();

        $gateway = $this->getActiveGateway();

        $storedVoices = VoiceBroadcast::latest()->get();

        return view('voice_broadcast.send_voice', [
            'reseller' => $reseller,
            'single' => false,
            'client' => null,
            'users' => $users,
            'confday' => config('app.billing_cycle'),
            'gateway' => $gateway,
            'storedVoices' => $storedVoices,
            'usableVoices' => $storedVoices->where('status', VoiceBroadcast::STATUS_ENABLED)->values(),
        ]);
    }

    /**
     * Store reusable voice asset in the library.
     */
    public function storeLibraryVoice(Request $request)
    {
        $request->validate([
            'voice' => 'required|file|mimetypes:audio/*',
            'title' => 'nullable|string|max:191',
        ]);

        $voiceFile = $request->file('voice');
        $voiceFileName = time() . '_' . Str::uuid()->toString() . '.' . $voiceFile->getClientOriginalExtension();
        $voicePath = $voiceFile->storeAs('voice_broadcasts', $voiceFileName, 'public');

        $voice = VoiceBroadcast::create([
            'title' => $request->input('title') ?: pathinfo($voiceFile->getClientOriginalName(), PATHINFO_FILENAME),
            'original_name' => $voiceFile->getClientOriginalName(),
            'file_path' => $voicePath,
            'file_size' => $voiceFile->getSize(),
            'mime_type' => $voiceFile->getMimeType(),
            'disk' => 'public',
            'created_by' => auth()->id(),
            'status' => VoiceBroadcast::STATUS_ENABLED,
        ]);

        return response()->json([
            'success' => 'Voice stored successfully.',
            'voice' => $voice,
        ]);
    }

    /**
     * Remove a saved voice asset.
     */
    public function destroyLibraryVoice(VoiceBroadcast $voiceBroadcast)
    {
        try {
            if ($voiceBroadcast->disk && $voiceBroadcast->file_path) {
                Storage::disk($voiceBroadcast->disk)->delete($voiceBroadcast->file_path);
            }
        } catch (\Throwable $th) {
            // ignore storage delete failure
        }

        $voiceBroadcast->delete();

        return response()->json(['success' => 'Voice removed from library.']);
    }

    /**
     * Resolve the voice file path based on upload or library selection.
     */
    private function resolveVoiceFile(Request $request): array
    {
        $source = $request->input('voice_source', 'upload');

        if ($source === 'library') {
            $voiceAsset = VoiceBroadcast::enabled()->find($request->voice_asset_id);
            if (!$voiceAsset) {
                throw new \RuntimeException('Selected voice file not found.');
            }

            $absolutePath = $voiceAsset->absolutePath();
            if (!file_exists($absolutePath)) {
                throw new \RuntimeException('Saved voice file is missing from storage.');
            }

            return [
                $voiceAsset->file_path,
                $absolutePath,
            ];
        }

        if (!$request->hasFile('voice')) {
            throw new \RuntimeException('Voice file is required.');
        }

        $voiceFile = $request->file('voice');
        $voiceFileName = time() . '_' . Str::uuid()->toString() . '.' . $voiceFile->getClientOriginalExtension();
        $voicePath = $voiceFile->storeAs('voice_broadcasts', $voiceFileName, 'public');
        $absolutePath = storage_path('app/public/' . $voicePath);

        if ($request->boolean('save_to_library')) {
            VoiceBroadcast::create([
                'title' => $request->input('voice_title') ?: pathinfo($voiceFile->getClientOriginalName(), PATHINFO_FILENAME),
                'original_name' => $voiceFile->getClientOriginalName(),
                'file_path' => $voicePath,
                'file_size' => $voiceFile->getSize(),
                'mime_type' => $voiceFile->getMimeType(),
                'disk' => 'public',
                'created_by' => auth()->id(),
                'status' => VoiceBroadcast::STATUS_ENABLED,
            ]);
        }

        return [$voicePath, $absolutePath];
    }

    /**
     * Update the status of a saved voice asset.
     */
    public function updateLibraryVoiceStatus(Request $request, VoiceBroadcast $voiceBroadcast)
    {
        $request->validate([
            'status' => ['required', Rule::in([VoiceBroadcast::STATUS_ENABLED, VoiceBroadcast::STATUS_DISABLED])],
        ]);

        $voiceBroadcast->update([
            'status' => $request->input('status'),
        ]);

        return response()->json([
            'success' => 'Voice status updated successfully.',
            'voice' => $voiceBroadcast->fresh(),
        ]);
    }

    /**
     * Send voice to selected customers
     */
    public function sendVoiceToSelected(Request $request)
    {
        $request->validate([
            'voice_source' => ['required', Rule::in(['upload', 'library'])],
            'voice' => 'required_if:voice_source,upload|file|mimetypes:audio/*',
            'voice_asset_id' => 'required_if:voice_source,library|exists:voice_broadcasts,id',
            'save_to_library' => 'nullable|boolean',
            'voice_title' => 'nullable|string|max:191',
        ]);

        $gateway = $this->getActiveGateway();

        if (!$gateway) {
            return response()->json(['error' => 'No active voice gateway configured. Please enable a voice gateway first.']);
        }

        try {
            [$voicePath, $voiceFilePath] = $this->resolveVoiceFile($request);

            $destinations = [];

             if ($request->singel_number && $request->singel_number !== "null") {
                 $len = strlen($request->singel_number);
                if ($len >= 11) {
                    $data = [
                        'contact' => $request->singel_number,
                        'voice_file_path' => $voiceFilePath,
                        'voice_file' => $voicePath,
                        'caller_id' => $gateway->caller_id,
                        'retry_count' => $gateway->retry_count,
                        'type' => 'voice_send'
                    ];

                    SendVoiceJob::dispatch($data);
                    return response()->json(['success' => 'Voice sent to ' . $request->singel_number . '. All Process In Queue']);
                } else {
                    return response()->json(['error' => 'Single Number Must be at least 11 digits']);
                }
            } elseif ($request->pop_id && $request->reseller_id && $request->billing_cycle && $request->status) {
                $statuses = is_array($request->status) ? $request->status : [$request->status];
                $dueFilter = $request->due_filter ?? 'all';
                if ($request->pop_id == 'all') {
                    $pop_ids = Pop::where('reseller_id', $request->reseller_id)->pluck('id');
                    if ($request->billing_cycle == 'all') {
                        $clients = Client::with(['clientsinfo', 'customerAccount'])
                            ->whereIn('pop_id', $pop_ids)
                            ->whereIn('clients_status', $statuses);
                    } else {
                        $clients = Client::with(['clientsinfo', 'customerAccount'])
                            ->whereIn('pop_id', $pop_ids)
                            ->whereIn('clients_status', $statuses)
                            ->where('billing_cycle', $request->billing_cycle);
                    }
                } else {
                    if ($request->billing_cycle == 'all') {
                        $clients = Client::with(['clientsinfo', 'customerAccount'])
                            ->where('pop_id', $request->pop_id)
                            ->whereIn('clients_status', $statuses);
                    } else {
                        $clients = Client::with(['clientsinfo', 'customerAccount'])
                            ->where('pop_id', $request->pop_id)
                            ->whereIn('clients_status', $statuses)
                            ->where('billing_cycle', $request->billing_cycle);
                    }
                }

                $areas = $request->input('areas', []);
                if (!is_array($areas)) {
                    $decodedAreas = json_decode($areas, true);
                    if (json_last_error() === JSON_ERROR_NONE && is_array($decodedAreas)) {
                        $areas = $decodedAreas;
                    } else {
                        $areas = $areas ? array_map('trim', explode(',', $areas)) : [];
                    }
                }
                $areas = array_filter($areas, function ($area) {
                    return $area !== null && $area !== '';
                });
                if (empty($areas)) {
                    $areas = ['all'];
                }

                if ($dueFilter === 'due') {
                    $clients = $clients->whereHas('customerAccount', function ($query) {
                        $query->where('dueAmount', '>', 0);
                    });
                } elseif ($dueFilter === 'without_due') {
                    $clients = $clients->where(function ($query) {
                        $query->whereHas('customerAccount', function ($accountQuery) {
                            $accountQuery->where('dueAmount', '<=', 0);
                        })->orWhereDoesntHave('customerAccount');
                    });
                }

                if (!in_array('all', $areas)) {
                    $clients = $clients->whereHas('clientsinfo', function ($query) use ($areas) {
                        $query->whereIn('area', $areas);
                    });
                }

                $clients = $clients->get();

                foreach ($clients as $client) {
                    if ($client->clientsinfo->contact_no) {
                        $data = [
                            'contact' => $client->clientsinfo->contact_no,
                            'voice_file_path' => $voiceFilePath,
                            'voice_file' => $voicePath,
                            'caller_id' => $gateway->caller_id,
                            'retry_count' => $gateway->retry_count,
                            'type' => 'voice_send'
                        ];

                        try {
                            SendVoiceJob::dispatch($data);
                        } catch (\Throwable $th) {
                            // Handle error silently
                        }
                    }
                }

                if (count($clients) > 0) {
                    return response()->json(['success' => 'Total Customer: ' . count($clients) . '. All Process In Queue']);
                } else {
                    return response()->json(['error' => 'No Customer Found']);
                }
            } else {
                return response()->json(['error' => 'Required all input']);
            }
        } catch (\Exception $e) {
            return response()->json(['error' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Send voice to users
     */
    public function sendVoiceToSelectedUser(Request $request)
    {
        $request->validate([
            'voice_source' => ['required', Rule::in(['upload', 'library'])],
            'voice' => 'required_if:voice_source,upload|file|mimetypes:audio/*',
            'voice_asset_id' => 'required_if:voice_source,library|exists:voice_broadcasts,id',
            'save_to_library' => 'nullable|boolean',
            'voice_title' => 'nullable|string|max:191',
        ]);

        $gateway = $this->getActiveGateway();

        if (!$gateway) {
            return response()->json(['error' => 'No active voice gateway configured. Please enable a voice gateway first.']);
        }

        try {
            [$voicePath, $voiceFilePath] = $this->resolveVoiceFile($request);

            $destinations = [];

            $totalUsers = 0;

            $selectedUsers = $request->users;
            if ($selectedUsers && !is_array($selectedUsers)) {
                $selectedUsers = [$selectedUsers];
            }

            if ($selectedUsers && in_array('all_user', $selectedUsers)) {
                $users = User::where('id', '>', 1)
                    ->where('email', '!=', 'soiket@outlook.com')
                    ->where('email', '!=', 'support@yetfix.com')
                    ->get();

                foreach ($users as $user) {
                    if ($user->mobile_number) {
                        $data = [
                            'contact' => $user->mobile_number,
                            'voice_file_path' => $voiceFilePath,
                            'voice_file' => $voicePath,
                            'caller_id' => $gateway->caller_id,
                            'retry_count' => $gateway->retry_count,
                            'type' => 'user_voice_send'
                        ];

                        try {
                            SendVoiceJob::dispatch($data);
                            $totalUsers++;
                        } catch (\Throwable $th) {
                            // Handle error silently
                        }
                    }
                }
            } else if ($selectedUsers && in_array('all_manager', $selectedUsers)) {
                $resellers = Reseller::get();
                foreach ($resellers as $reseller) {
                    if ($reseller->contact) {
                        $data = [
                            'contact' => $reseller->contact,
                            'voice_file_path' => $voiceFilePath,
                            'voice_file' => $voicePath,
                            'caller_id' => $gateway->caller_id,
                            'retry_count' => $gateway->retry_count,
                            'type' => 'manager_voice_send'
                        ];

                        try {
                            SendVoiceJob::dispatch($data);
                            $totalUsers++;
                        } catch (\Throwable $th) {
                            // Handle error silently
                        }
                    }
                }
            } else if ($selectedUsers) {
                $users = User::whereIn('id', $selectedUsers)->get();
                foreach ($users as $user) {
                    if ($user->mobile_number) {
                        $data = [
                            'contact' => $user->mobile_number,
                            'voice_file_path' => $voiceFilePath,
                            'voice_file' => $voicePath,
                            'caller_id' => $gateway->caller_id,
                            'retry_count' => $gateway->retry_count,
                            'type' => 'user_voice_send'
                        ];

                        try {
                            SendVoiceJob::dispatch($data);
                            $totalUsers++;
                        } catch (\Throwable $th) {
                            // Handle error silently
                        }
                    }
                }
            }

            if ($totalUsers > 0) {
                return response()->json(['success' => 'Total Users: ' . $totalUsers . '. All Process In Queue']);
            } else {
                return response()->json(['error' => 'No users found']);
            }
        } catch (\Exception $e) {
            return response()->json(['error' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Send reminder voice to due customers before expiry
     */
    public function sendVoiceReminder(Request $request)
    {
        $request->validate([
            'voice_source' => ['required', Rule::in(['upload', 'library'])],
            'voice' => 'required_if:voice_source,upload|file|mimetypes:audio/*',
            'voice_asset_id' => 'required_if:voice_source,library|exists:voice_broadcasts,id',
            'save_to_library' => 'nullable|boolean',
            'voice_title' => 'nullable|string|max:191',
            'days_before' => 'required|integer|min:1|max:60',
        ]);

        $gateway = $this->getActiveGateway();

        if (!$gateway) {
            return response()->json(['error' => 'No active voice gateway configured. Please enable a voice gateway first.']);
        }

        try {
            [$voicePath, $voiceFilePath] = $this->resolveVoiceFile($request);

            $daysBefore = (int) $request->days_before;
            $targetDate = Carbon::today()->addDays($daysBefore);

            $clients = Client::with(['clientsinfo', 'customerAccount'])
                ->whereDate('expire_date', $targetDate)
                ->whereHas('customerAccount', function ($query) {
                    $query->where('dueAmount', '>', 0);
                })
                ->get();

            $total = 0;

            foreach ($clients as $client) {
                if ($client->clientsinfo && $client->clientsinfo->contact_no) {
                    $data = [
                        'contact' => $client->clientsinfo->contact_no,
                        'voice_file_path' => $voiceFilePath,
                        'voice_file' => $voicePath,
                        'caller_id' => $gateway->caller_id,
                        'retry_count' => $gateway->retry_count,
                        'type' => 'due_reminder_voice_send'
                    ];

                    try {
                        SendVoiceJob::dispatch($data);
                        $total++;
                    } catch (\Throwable $th) {
                        // continue silently
                    }
                }
            }

            if ($total > 0) {
                return response()->json(['success' => 'Reminder voice queued for ' . $total . ' customers.']);
            }

            return response()->json(['error' => 'No due customers found within the selected timeframe.']);
        } catch (\Exception $e) {
            return response()->json(['error' => 'Error: ' . $e->getMessage()]);
        }
    }

    /**
     * Show the reminder voice SMS schedule settings page
     */
    public function reminderSchedule()
    {
        $companyInfo = CompanyInformation::latest()->first();
        $daysBefore = 3; // Default: 3 days
        $scheduleTime = '11:30'; // Default time
        $voiceId = null; // Default: use latest enabled voice

        if ($companyInfo && $companyInfo->settings) {
            $settings = json_decode($companyInfo->settings);
            $scheduleSetting = collect($settings)->where('type', 'voice_reminder_schedule')->first();
            if ($scheduleSetting) {
                $daysBefore = $scheduleSetting->days_before ?? 3;
                $scheduleTime = $scheduleSetting->time ?? '11:30';
                $voiceId = $scheduleSetting->voice_id ?? null;
            }
        }

        // Get all enabled voices for selection
        $enabledVoices = VoiceBroadcast::enabled()->latest()->get();

        return view('voice_broadcast.reminder_schedule', [
            'daysBefore' => $daysBefore,
            'scheduleTime' => $scheduleTime,
            'voiceId' => $voiceId,
            'enabledVoices' => $enabledVoices,
        ]);
    }

    /**
     * Store the reminder voice SMS schedule settings
     */
    public function storeReminderSchedule(Request $request)
    {
        $request->validate([
            'days_before' => 'required|integer|min:1|max:60',
            'schedule_time' => 'required|date_format:H:i',
            'voice_id' => 'nullable|exists:voice_broadcasts,id',
        ], [
            'days_before.required' => 'Days before expire date is required.',
            'days_before.integer' => 'Days before must be a number.',
            'days_before.min' => 'Days before must be at least 1.',
            'days_before.max' => 'Days before must not exceed 60.',
            'schedule_time.required' => 'Schedule time is required.',
            'schedule_time.date_format' => 'Invalid time format. Please use HH:MM format (e.g., 11:30).',
            'voice_id.exists' => 'Selected voice file does not exist.',
        ]);

        $companyInfo = CompanyInformation::latest()->first();

        if (!$companyInfo) {
            Toastr::error('Company information not found.', 'Error');
            return redirect()->back();
        }

        $settings = [];
        if ($companyInfo->settings) {
            $settings = json_decode($companyInfo->settings, true);
        }

        // Remove existing voice_reminder_schedule if exists
        $settings = array_filter($settings, function ($item) {
            return isset($item['type']) && $item['type'] !== 'voice_reminder_schedule';
        });

        // Add new voice_reminder_schedule setting
        $settings[] = [
            'type' => 'voice_reminder_schedule',
            'days_before' => (int) $request->days_before,
            'time' => $request->schedule_time,
            'voice_id' => $request->voice_id ? (int) $request->voice_id : null,
        ];

        // Re-index array to ensure proper JSON encoding
        $settings = array_values($settings);

        $companyInfo->settings = json_encode($settings);
        $companyInfo->save();

        // Clear cache so scheduler picks up the new settings
        cache()->forget('companyinfo');

        Toastr::success('Reminder voice SMS schedule updated successfully. The schedule will take effect after the next cron run.', 'Success');
        return redirect()->back();
    }
}
