<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\Message;
use App\Models\PromotionMail;
use Illuminate\Support\Facades\DB;
use App\Models\Prompt;
use App\Models\Sentiment;
use App\Models\SentMail;
use App\Models\User;
use App\Http\Controllers\AuthController;
use App\Models\Freshcount;
use App\Models\ProjectResponse;
use DateTime;
use DateTimeZone;
use Firebase\JWT\JWT;
use Illuminate\Support\Facades\Validator;

class MailController extends Controller
{
    //
    public function show($employee_id = null)
    {
        if (!Auth::check()) {
            header('Location: ' . route('login'));
            exit();
        }
        // return $employee_id;
        $counts = $this->common($employee_id);
        $prompts = Prompt::where('user_id', Auth::id())
            ->orderBy('created_at', 'desc')
            ->get();
        // Default: Auth user
        $email = Auth::user()->email;


        // Try employee fetch only if $employee_id is passed
        if ($employee_id) {
            $employee = User::where('id', $employee_id);
            //  $employee->where('auth_id', Auth::id());
            // ->first();
            //level wise
            $user_level = DB::table('users')->where('id', Auth::id())
                ->first();
            if ($user_level->user_level == 2) {
                $employee->where('auth_id', Auth::id());
            } elseif ($user_level->user_level == 1) {
                $employee->where('Department_head_id', Auth::id());
            } elseif ($user_level->user_level == 0) {
            } else {
            }

            $employee = $employee->first();
            // dd($employee);
            if ($employee) {
                return view('mailinfo', compact('counts', 'prompts', 'employee'));
            }
        }
        // dd($email);
        return view('mailinfo', compact('counts', 'prompts', 'email'));
    }
    public function common($employee_id = null)
    {
        $userId = $employee_id ?? Auth::id();

        $admin = \App\Models\User::where('id', $userId)
            ->where('auth_id', 0)
            ->select('id', 'email')
            ->first();
        $emailArray = [];
        if ($admin) {
            // echo "ID: " . $admin->id . "<br>";
            // echo "Email: " . $admin->email;
            $relatedUsers = User::where('auth_id', $admin->id)
                ->get();

            foreach ($relatedUsers as $relatedUser) {
                $emailArray[] = [
                    'id' => $relatedUser->id,
                    'email' => $relatedUser->email,
                ];
            }
            // Print email array
            // print_r($emailArray);
        }
        // die('<br>ee');


        if (is_null($userId)) {
            abort(403, 'Unauthorized action. Please first Login common function Error', ['Content-Type' => 'text/html']);
        }
        // $userId = Auth::id(); // Get logged-in user ID
        // $userId = 1;
        if (true) {
        } else {
            $sentMails = DB::table('sent_mails')
                ->where('user_id', $userId)
                ->where('matched_subject', '0')
                // ->where('sent_mail_id','21')
                ->get();
            // dd($sentMails);
            foreach ($sentMails as $mail) {
                // return;
                // echo $mail->id."<br>";
                if ($mail->sent_mail_id) {
                    $message = DB::table('messages')
                        ->where('user_id', $userId)
                        ->where('clean_subject', $mail->clean_subject)
                        ->where('sender_email', $mail->receiver_email)
                        ->where('sent_mail_id', '-1')
                        ->first();
                    // ->get();
                    // dd( $message);
                    if ($message) {
                        // 2. Update the message to attach it with sent_mail_id
                        $update_messages = DB::table('messages')
                            ->where('id', $message->id)
                            ->update([
                                'sent_mail_id' => $mail->sent_mail_id,
                                'sent_date_s' => $mail->sent_date_s,
                                'message_status' => '1'
                            ]);
                        // echo "1";
                        // echo $update_messages;
                        // dd($update_messages);
                        // 3. Update matched_subject = 1 in current sent_mail row
                        $update_sent_mails = DB::table('sent_mails')
                            ->where('id', $mail->id)
                            ->update([
                                'matched_subject' => 1
                            ]);
                        // echo "2";
                        // echo $update_sent_mails;
                        // dd($update_sent_mails);
                    }
                    // dd("heello");
                }
            }
        }
        // dd("heello");
        // Return data as an associative array
        $user_data = DB::table('users')->where('id', $userId)->first();
        $email = $user_data->email ?? null;

        // Counts follow the same rule as filterMails(): mails the user sent themselves
        // are counted everywhere except the two reply-tracking buckets below.
        $notOwnMail = function ($query) use ($email) {
            return $email ? $query->where('sender_email', '!=', $email) : $query;
        };

        // The sentiment vocabulary is admin-managed, so the chips are built from
        // it rather than from three fixed keys. One grouped query serves every
        // label: a query per label would grow with the admin's list.
        // The two branches below differ in their predicate — the live one filters
        // on the spam label, the other excludes the user's own mail — so each
        // gets counts computed the same way its old per-label queries were.
        $sentimentDefs = $this->sentimentChipDefinitions();
        $sentimentCounts = $this->sentimentCounts($userId, null, true);
        $sentimentCountsExcludingOwn = $this->sentimentCounts($userId, $email, false);

        if (true) {
            // echo "Related Users:<br>";
            // print_r($emailArray);
            return [
                'employee_data' => $emailArray,

                'countAll' => Message::where('user_id', $userId)->distinct('email_id')->count('id'), // Total unique messages
                'countUnread' => Message::where('user_id', $userId)->where('message_status', 0)->distinct('email_id')->count('id'), // Unread messages
                'countRead' => Message::where('user_id', $userId)->where('message_status', 1)->distinct('email_id')->count('id'), // Read messages

                // Every active sentiment, keyed by its filter slug, plus the
                // label/colour metadata the toolbar needs to render them.
                'sentiments' => $sentimentCounts,
                'sentiment_defs' => $sentimentDefs,
                'sentimentTotal' => array_sum($sentimentCounts),

                // The three original keys, still read by the daily summary mail
                // and the employee list. They resolve through the slugs the
                // standard labels carry, so they are the same numbers as before.
                'countis_not_spam' => $sentimentCounts['is_not_spam'] ?? 0,
                'countis_spam' => $sentimentCounts['is_spam'] ?? 0,
                'neutral' => $sentimentCounts['neutral'] ?? 0,

                'promotion' => Message::where('user_id', $userId)->where('is_promotion', '!=', '0')->where('message_status', 0)->distinct('email_id')->count('id'),

                // Mirrors the 'send-mail' branch of filterMails() so the chip matches the list.
                'send-mail' => $notOwnMail(Message::where('user_id', $userId))->where('is_promotion', '0')->where('track_reply_email', '0')->where('action_required', 1)->where('message_status', 0)->distinct('email_id')->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])->count('id'),
                // Mirrors the 'replied_mail' branch of filterMails() so the chip matches the list.
                'replied_mail' => $notOwnMail(Message::where('user_id', $userId))->where('action_required', 1)->where('is_promotion', '0')->where('track_reply_email', '!=', '0')->whereNotNull('track_reply_email')->distinct('email_id')->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])->count('id'),

                // 'track_mail' => Message::where('user_id', $userId)->where('is_spam', 2)->where('root_email_id', '!=', 0)->where('message_status', 0)->distinct('email_id')->count('id'),
                // 'track_mail' => Message::where('user_id', $userId)->where('is_spam', 2)->where('root_email_id', '!=', 0)->where('track_reply_email', 0)->where('message_status', 0)->distinct('email_id')->count('id'),

                'sales' => Message::where('user_id', $userId)->where('category', 1)->where('is_promotion', '=', '0')->where('message_status', 0)->distinct('email_id')->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])->count('id'),
                'amc' => Message::where('user_id', $userId)->where('category', 2)->where('is_promotion', '=', '0')->where('message_status', 0)->distinct('email_id')->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])->count('id'),

                'countis_not_spam_heading' => Prompt::where('user_id', $userId)->where('status', 0)->pluck('keywords')->first(),
            ];
        } else {
            // echo "Related Users:<br>";
            // print_r($emailArray);
            return [
                'employee_data' => $emailArray,

                'countAll' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->distinct('email_id')->count('id'), // Total unique messages
                'countUnread' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->where('message_status', 0)->distinct('email_id')->count('id'), // Unread messages
                'countRead' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->where('message_status', 1)->distinct('email_id')->count('id'), // Read messages

                'sentiments' => $sentimentCountsExcludingOwn,
                'sentiment_defs' => $sentimentDefs,
                'sentimentTotal' => array_sum($sentimentCountsExcludingOwn),

                'countis_not_spam' => $sentimentCountsExcludingOwn['is_not_spam'] ?? 0,
                'countis_spam' => $sentimentCountsExcludingOwn['is_spam'] ?? 0,
                'neutral' => $sentimentCountsExcludingOwn['neutral'] ?? 0,

                'promotion' => Message::where('user_id', $userId)->where('is_promotion', '!=', '0')->where('sender_email', '!=', $email)->where('message_status', 0)->distinct('email_id')->count('id'),

                'send-mail' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->where('sent_mail_id', '-1')->where('action_required', 1)->distinct('email_id')->count('id'),
                'replied_mail' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->where('sent_mail_id', '!=', '-1')->distinct('email_id')->count('id'),

                // 'track_mail' => Message::where('user_id', $userId)->where('is_spam', 2)->where('root_email_id', '!=', 0)->where('message_status', 0)->distinct('email_id')->count('id'),
                // 'track_mail' => Message::where('user_id', $userId)->where('is_spam', 2)->where('root_email_id', '!=', 0)->where('track_reply_email', 0)->where('message_status', 0)->distinct('email_id')->count('id'),            

                'sales' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->where('category', 1)->where('message_status', 0)->distinct('email_id')->count('id'),
                'amc' => Message::where('user_id', $userId)->where('sender_email', '!=', $email)->where('category', 2)->where('message_status', 0)->distinct('email_id')->count('id'),

                'countis_not_spam_heading' => Prompt::where('user_id', $userId)->where('status', 0)->pluck('keywords')->first(),
            ];
        }
    }

    public function filterMails($type, $employee_id = null)
    {
        if (!Auth::check()) {
            header('Location: ' . route('login'));
            exit();
        }
        // $counts_not_use = $this->common($employee_id);//its not use anywhere 
        $userId = $employee_id ?? Auth::id();
        if (preg_match('/^search-(.+)$/', $type, $matches)) {
            $type = 'search'; // Fixed prefix
            $searchText = $matches[1]; // The text after 'search-'

            $search_id_group = explode('-', $searchText);
            $groupId = $search_id_group[0];
        } else {
            // Not a search type
            $searchType = $type;
            $search_id_group = '';
        }
        // echo $search_id_group[0];
        // dd($type);

        // $userId = Auth::id();
        // dd($userId);
        // DB::enableQueryLog();
        $query = Message::where('user_id', $userId)
            ->distinct('email_id');
        // dd(DB::getQueryLog());
        // ->orderBy('id', 'desc');
        // ->orderBy('email_id', 'desc');

        $user = DB::table('users')->where('id', $userId)->first();
        $email = $user->email ?? null;

        // Mails the user sent themselves stay in the listing. Only the reply-tracking
        // buckets drop them, because you never owe yourself a reply.
        $excludeOwnMail = function () use ($query, $email) {
            if ($email) {
                $query->where('sender_email', '!=', $email);
            }
        };
        if (true) {
            // Sentiment filters are resolved from the admin-managed vocabulary
            // first, so a new label is filterable the moment it is added. A slug
            // the vocabulary does not claim falls through to the fixed filters.
            $sentimentLabel = $this->applySentimentFilter($query, (string) $type, true);

            // $type = "All Mail";
            if ($sentimentLabel !== false) {
                $type = $sentimentLabel;
            } elseif ($type == 'all') {
                //if is true they get all mail
                $type = "All Mail";
            } elseif ($type == 'search') {

                $imp_mails = DB::table('impmail')
                    ->where('group_id', $groupId)
                    ->orderBy('id', 'asc')
                    ->get();
                $senderEmails = $imp_mails->pluck('sender_email')->unique()->values();
                $query->whereIn('sender_email', $senderEmails);
                $groups = DB::table('inbox_groups')->where('id', $groupId)->first();
                // dd($groups);
                $type = "Group " . $groups->group_name;
            } elseif ($type == 'read') {
                $query->where('message_status', 1);
                $type = "Read Mail";
            } elseif ($type == 'unread') {
                $query->where('message_status', 0);
                $type = "Un-Read Mail";
            } elseif ($type == 'send-mail') {
                // Only send-mail emails
                $excludeOwnMail();
                $query->where('action_required', 1)
                    ->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])
                    ->where('is_promotion', '=', '0')
                    ->where('track_reply_email', '0')
                    ->where('message_status', 0);
                $type = 'Reply pending mail';
            } elseif ($type == 'promotion') {
                $query
                    ->where('message_status', 0)->where('is_promotion', '!=', '0'); // Only promotion emails
                $type = "Promotion Mail";
            } elseif ($type == 'sales') {
                $query->where('category', 1)
                    ->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])
                    ->where('is_promotion', '=', '0')
                    ->where('message_status', 0); // Only sales emails
                $type = "Sales";
            } elseif ($type == 'amc') {
                $query->where('category', 2)
                    ->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])
                    ->where('is_promotion', '=', '0')
                    ->where('message_status', 0); // Only amc emails
                $type = "AMC";
            } elseif ($type == 'replied_mail') {
                // $query->where('track_reply_email', '!=', '0');
                $excludeOwnMail();
                $query->where('action_required', 1)
                    ->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%'])
                    ->where('track_reply_email', '!=', '0')
                    ->where('is_promotion', '=', '0')
                    ->whereNotNull('track_reply_email');
                $type = "Replied Mail";
            }
        } else {
            // As above, but this branch never applied the spam-label clause.
            $sentimentLabel = $this->applySentimentFilter($query, (string) $type, false);

            // $type = "All Mail";
            if ($sentimentLabel !== false) {
                $type = $sentimentLabel;
            } elseif ($type == 'all') {
                //if is true they get all mail
                $type = "All Mail";
            } elseif ($type == 'read') {
                $query->where('message_status', 1);
                $type = "Read Mail";
            } elseif ($type == 'unread') {
                $query->where('message_status', 0);
                $type = "Un-Read Mail";
            } elseif ($type == 'send-mail') {
                // Only send-mail emails
                $excludeOwnMail();
                $query->where('action_required', 1)
                    ->where('sent_mail_id', '-1')
                    ->where('message_status', 0);
                $type = 'Reply pending mail';
            } elseif ($type == 'promotion') {
                $query->where('message_status', 0)->where('is_promotion', '!=', '0'); // Only promotion emails
                $type = "Promotion Mail";
            } elseif ($type == 'sales') {
                $query->where('category', 1)->where('message_status', 0); // Only sales emails
                $type = "Sales";
            } elseif ($type == 'amc') {
                $query->where('category', 2)->where('message_status', 0); // Only amc emails
                $type = "AMC";
            } elseif ($type == 'replied_mail') {
                $excludeOwnMail();
                $query->where('sent_mail_id', '!=', '-1');
                $type = "Replied Mail";
            }
        }
        $mails = $query
            ->orderBy('id', 'desc')->get();
        $mails = $mails->unique('email_id')->values();
        $counts = $this->common($employee_id);
        if ($employee_id) {
            $data = User::where('id', $employee_id);
            //level wise
            $user_level = DB::table('users')->where('id', Auth::id())
                ->first();
            if ($user_level->user_level == 2) {
                $data->where('auth_id', Auth::id());
            } elseif ($user_level->user_level == 1) {
                $data->where('Department_head_id', Auth::id());
            } elseif ($user_level->user_level == 0) {
            } else {
            }
            // $data->where('auth_id', Auth::id());
            $employee = $data->first();

            // $counts = $this->common($employee->id);
            // dd($mails);

            if ($employee) {
                return view('mail.index', compact('mails', 'type', 'counts', 'employee'));
            }
        }
        return view('mail.index', compact('mails', 'type', 'counts'));
    }

    public function single_mail($mail_id, $is_sent = 0, $employee_id = null)
    {
        $email_id = $mail_id;
        // $userId = Auth::id();
        // dd($employee_id);
        $userId = $employee_id ?? Auth::id();
        // Fetch Single Mail Data
        $mail = Message::where('email_id', $mail_id)
            ->where('user_id', $userId)
            ->first(); // Fetch only one record
        if (true) {
        } else {
            if ($is_sent) {
                $mail = SentMail::where('sent_mail_id', $mail_id)
                    ->where('user_id', $userId)
                    ->first();
            }
        }
        // else {
        //     if ($mail) {
        //         $mail->message_status = 1;
        //         $mail->save();
        //     }
        // }
        // dd($mail->id);
        // Check if Mail Exists
        if (!$mail) {
            return 'Mail Not Found Here Mail id not found please chek code';
            return abort(404, 'Mail Not Found Here Mail id not found please chek code'); // Show 404 if not found
        }
        // Function to clean the message content
        function cleanText($text)
        {
            return preg_replace('/[\x{200C}\x{2007}\x{AD}\x{FEFF}]/u', '', $text);
        }
        $mail->message = cleanText($mail->message);

        // Opening a mail is what marks it read. This has to run before common()
        // below, otherwise the chip counts rendered on this very page still
        // carry the pre-open unread number and the mail reads as unread while
        // the user is looking straight at it.
        $this->markMailRead($mail_id, $userId);
        $mail->message_status = '1';

        // dd($mail);
        $counts = $this->common($employee_id);
        if ($employee_id) {
            // $employee = User::where('id', $employee_id)
            //     ->where('auth_id', Auth::id())
            //     ->first();
            $data = User::where('id', $employee_id);
            //level wise
            $user_level = DB::table('users')->where('id', Auth::id())
                ->first();
            if ($user_level->user_level == 2) {
                $data->where('auth_id', Auth::id());
            } elseif ($user_level->user_level == 1) {
                $data->where('Department_head_id', Auth::id());
            } elseif ($user_level->user_level == 0) {
            } else {
            }
            // $data->where('auth_id', Auth::id());
            $employee = $data->first();
            // dd($employee);
            if ($employee) {
                return view('mail.single', compact('email_id', 'counts', 'mail', 'employee', 'is_sent'));
            }
        }
        $employee = Null;
        return view('mail.single', compact('email_id', 'counts', 'mail', 'employee', 'is_sent'));
    }

    public function show_single_mail($mail_id, $is_sent = 0, $employee_id = null)
    {
        $email_id = $mail_id;
        // $userId = Auth::id();
        // dd($employee_id);
        $userId = $employee_id ?? Auth::id();
        // Fetch Single Mail Data
        $mail = Message::where('email_id', $mail_id)
            ->where('user_id', $userId)
            ->first(); // Fetch only one record
        if (true) {
        } else {
            if ($is_sent) {
                $mail = SentMail::where('sent_mail_id', $mail_id)
                    ->where('user_id', $userId)
                    ->first();
            }
        }
        // else {
        //     if ($mail) {
        //         $mail->message_status = 1;
        //         $mail->save();
        //     }
        // }
        // dd($mail->id);
        // Check if Mail Exists
        if (!$mail) {
            return 'Mail Not Found Here Mail id not found please chek code';
            return abort(404, 'Mail Not Found Here Mail id not found please chek code'); // Show 404 if not found
        }
        // Function to clean the message content
        function cleanText($text)
        {
            return preg_replace('/[\x{200C}\x{2007}\x{AD}\x{FEFF}]/u', '', $text);
        }
        $mail->message = cleanText($mail->message);

        // Opening a mail is what marks it read. This has to run before common()
        // below, otherwise the chip counts rendered on this very page still
        // carry the pre-open unread number and the mail reads as unread while
        // the user is looking straight at it.
        $this->markMailRead($mail_id, $userId);
        $mail->message_status = '1';

        // dd($mail);
        $counts = $this->common($employee_id);
        if ($employee_id) {
            // $employee = User::where('id', $employee_id)
            //     ->where('auth_id', Auth::id())
            //     ->first();
            $data = User::where('id', $employee_id);
            //level wise
            $user_level = DB::table('users')->where('id', Auth::id())
                ->first();
            if ($user_level->user_level == 2) {
                $data->where('auth_id', Auth::id());
            } elseif ($user_level->user_level == 1) {
                $data->where('Department_head_id', Auth::id());
            } elseif ($user_level->user_level == 0) {
            } else {
            }
            // $data->where('auth_id', Auth::id());
            $employee = $data->first();
            // dd($employee);
            if ($employee) {
                return view('mail.show_single', compact('email_id', 'counts', 'mail', 'employee', 'is_sent'));
            }
        }
        $employee = Null;
        return view('mail.show_single', compact('email_id', 'counts', 'mail', 'employee', 'is_sent'));
    }
    public function customLogWriter(
        string $filePath,
        string $email = 'NO HAVE EMAIL ID',
        string $userId = 'NO HAVE USER ID',
        string $message = 'NO MESSAGE',
        int $startEolCount = 0,
        int $endEolCount = 0
    ) {
        date_default_timezone_set('Asia/Kolkata');
        $time = date('H:i:s');
        $date = date('d/m/y');

        // Limit both counts between 0 and 4
        $startEolCount = max(0, min(4, $startEolCount));
        $endEolCount   = max(0, min(4, $endEolCount));

        // Prepare gaps
        $startGap = str_repeat(PHP_EOL, $startEolCount);
        $endGap   = str_repeat(PHP_EOL, $endEolCount);

        // Prepare log message
        $logMessage  = $startGap;
        $logMessage .= "[$date $time] Email: $email | User ID: $userId | Message: $message" . PHP_EOL;
        $logMessage .= $endGap;

        // Write to file
        file_put_contents($filePath, $logMessage, FILE_APPEND);
    }

    function callFlaskAPI($value, $api_url = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=',  $apiname = 'Geminiapi-flash',  $Categorization = 'usefull', $ai_Prompt = null)
    {
        // echo "<br>enter gemini api calling";
        $email_content = $value;
        $is_variable = $Categorization;
        // $is_variable = "usefull";
        $not_variable = "not " . $is_variable;
        $reason_variable = $ai_Prompt;

        $categorised_based_on_text = "You are an expert email analyzer.

        Your task is to analyze only the reply portion of the email — strictly ignore any quoted text or previous message threads. That includes:
        - Any line starting with '> '
        - Any section starting with lines like: 'On [date], [person] wrote:' or similar.
        If no meaningful reply is found, or the email is unclear, still respond with default values.

        Respond with a **valid JSON only**, with these 4 fields:

        1. \"action_required\":
        - \"send-mail\" → if the reply asks a question, requests help, or needs a response/action  
        - \"no-action\" → otherwise

        2. \"sentiment\":  
{$this->sentimentPromptSection()}

        3. \"category\":  
        - if emails related to AMC (Annual Maintenance Contracts), including contract renewals,
            maintenance schedules, service reports, or warranty-related communication. amc related Business-inquiry
            These emails often include words like: AMC, annual maintenance, service due, contract renewal, preventive maintenance, next visit, service report
        maintenance visit, warranty, SLA, support contract, service schedule, service invoice. → \"amc\"  
        
        - If personalized or business-to-business emails where a product/service is being pitched or 
        discussed directly. These emails often contain words like: proposal but not amc proposal, quotation but not amc quotation, 
        or not amc related Business-inquiry ,or not amc related lead ,or not amc related solution ,or not amc related offering,or not amc related business opportunity
        lead, solution, offering, Business-inquiry, sales team, contact us, client requirement, business opportunity.
                → \"sales\"  
                
        - If the mail is about public communication, media, press release, uploading to website/social media (SM), or includes domains like `@adfactorspr.com` → \"external\"  
        - Else → \"external\"

        4. \"summary\":
        - ALWAYS summarise the email in 1-2 sentences: what it is about and what the sender wants, reports or decides.
        - Unlike the fields above, this field applies to the WHOLE email. Summarise the newest message; use the quoted thread beneath it only as context, never summarise the quoted thread on its own.
        - Required for every email, including first-time (non-reply) mails, newsletters, notifications and promotions.
        - Plain text only. No HTML, no markdown, no newlines. Keep it under 300 characters.
        - Use \"No summary available\" ONLY when the email body is completely empty.

        Even if uncertain, **always return all 4 fields** with your best guess or default values.
        Return raw JSON only — no code fences, and no trailing comma before the closing brace.

        Example:
        {\"action_required\": \"no-action\", \"sentiment\": \"{$this->sentimentFallbackCode()}\", \"category\": \"external\", \"summary\": \"Vendor shared the revised AMC quotation and asked for confirmation by Friday.\"}

        Email:
        \"$email_content\"";
        $promptText = "$categorised_based_on_text\n\nQuestion: $email_content";
        $apiKey = env('GEMINI_API_KEY'); //paid api key
        $endpoint = $api_url . $apiKey;

        $postData = [
            'contents' => [
                [
                    'role' => 'user',
                    'parts' => [
                        ['text' => $promptText]
                    ]
                ]
            ]
        ];
        // echo "<br>Calling start gemini api calling";
        $ch = curl_init($endpoint);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        $company_name = "Internal UAT Mukesoft";
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'X-App-ID: '  . $company_name . ''
        ]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
        curl_setopt($ch, CURLOPT_TIMEOUT, 45);

        $response = curl_exec($ch);

        if (curl_errno($ch)) {
            echo "cURL Error: " . curl_error($ch);
            curl_close($ch);
            die("<br>API Not Working: cURL Error -> " . curl_error($ch));
            return false; // Agar error ho to false return karo
        }
        // echo "<br>Getting Responce with gemini api calling";
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        // echo $httpCode;


        curl_close($ch); // cURL Close Karein

        // JSON Response Decode Karna
        $data = json_decode($response, true);
        // dd($data);

        $inputTokens  = 0;
        $outputTokens = 0;
        $totalTokens  = 0;
        if(isset($data['usageMetadata'])){
            $inputTokens  = $data['usageMetadata']['promptTokenCount'] ?? 0;
            $outputTokens = $data['usageMetadata']['candidatesTokenCount'] ?? 0;
            $totalTokens  = $data['usageMetadata']['totalTokenCount'] ?? 0;
        }

        $error_message = [
            'application'   => $apiname,
            'domain'        => request()->getHost(),
            'API URL'       => $api_url,
            'input_tokens'  => $inputTokens,
            'output_tokens' => $outputTokens,
            'total_tokens'  => $totalTokens
        ];

        $logMessage = json_encode($error_message) . PHP_EOL;

        file_put_contents(
            storage_path('logs/Gemini_token_error.log'),
            $logMessage,
            FILE_APPEND
        );

        date_default_timezone_set('Asia/Kolkata');
        $time = date('H:i:s');        // Hour:Minute:Second
        $date = date('d/m/y');
        $dataString = print_r($data, true);
        //k0530 11-05-2025 --new 
        $company_name = request()->getHost();
        ProjectResponse::create([
            'project' => $company_name,
            'input' => $email_content,
            'gemini_response' => print_r($data, true)
        ]);
        //k0530 11-05-2025 --new 
        // without app password
        $falsklogFile =  storage_path('logs/MailController_flask_Api_log.txt');
        $flasklogMessage = PHP_EOL . str_repeat(PHP_EOL, 3) . "[$date $time] Message:  ia m falsk api :- [$dataString]" . PHP_EOL;
        // file_put_contents($falsklogFile, $flasklogMessage, FILE_APPEND);


        // HTTP Status Code Handling
        if ($httpCode == 404) {
            $dataString = print_r($data, true);
            $this->customLogWriter(storage_path('logs/MailController_flask_Api_log.txt'), 'flask method Mail Controller', $apiname . ' 404', $dataString, 1, 1);
            return [
                'message' => 'Predict Api not working ...! please check this api',
                'status' => false,
                'code' => 250
            ];
            echo "<br>Error 404: API Endpoint Not Found. Please check the URL: " . $url;
            die("<br>API Not Working: Error 404 - API Endpoint Not Found. Please check the URL: " . $url);
            return false;
        } elseif ($httpCode == 500) {
            $this->customLogWriter(storage_path('logs/MailController_flask_Api_log.txt'), 'flask method Mail Controller ', $apiname . ' 500', $dataString, 1, 1);
            return [
                'message' => 'Predict Api not working ...! please check this api 500',
                'status' => false,
                'code' => 250
            ];
            echo "<br>Error 500: Server Error. Check Gemini API logs." . $response;
            die("<br>API Not Working: Error 500 - Server Error. Check Flask API logs.");
            return false;
        } elseif ($httpCode == 403) {
            $this->customLogWriter(storage_path('logs/MailController_flask_Api_log.txt'), 'flask method Mail Controller ', $apiname . ' 403', $dataString, 1, 1);
            return [
                'message' => 'The provided API key has an IP address restriction.',
                'status' => false,
                'code' => 403
            ];
            echo "<br>Error 403: Gemini Api Error. Check Gemini API logs." . $response;
            die("<br>API Not Working: Error 403 - Server Error. Check Flask API logs.");
            return false;
        } elseif ($httpCode == 503) {
            $this->customLogWriter(storage_path('logs/MailController_flask_Api_log.txt'), 'flask method Mail Controller', $apiname . ' 503', $dataString, 1, 1);
            return [
                'message' => 'The model is overloaded. Please try again later.',
                'status' => false,
                'code' => 503
            ];
            echo "<br>Error 500: Server Error. Check Gemini API logs." . $response;
            die("<br>API Not Working: Error 500 - Server Error. Check Flask API logs.");
            return false;
        }

        // echo "<pre>";
        // print_r($data);
        $request_error_code = $data['error']['code'] ?? null;
        if (isset($request_error_code)) {
            // echo "<pre>";
            // print_r($data);
            // echo  $request_error_code;
            // die ;
            $this->customLogWriter(storage_path('logs/MailController_flask_Api_log.txt'), 'flask method Mail Controller', $apiname . ' another no', $dataString, 1, 1);
            return [
                'message' => 'callFlaskAPI occure issue ai cant handle 15-20 request please wait and try anothor time',
                'status' => false,
                //Use the API every day for free, as long as you don’t exceed:1,500 requests per day, and 15 requests per minute, and 1 million tokens per minute
                'code' => $request_error_code //"code": 429 this belongs to handle request is | *Requests per minute (RPM)*   | *15 requests* per minute   
            ];
        }

        $decodedResponse = $data['candidates'][0]['content']['parts'][0]['text'] ?? null;
        // echo  $decodedResponse;
        // echo "hello";

        if (isset($decodedResponse)) {
            $category = $decodedResponse;

            // Return the model text as-is: callers normalise the classification
            // values themselves (aiFieldValue) and "summary" must keep its casing.
            return trim($category);
            if (strtolower(trim($category)) === "positive") {
                $result = 1;
            } elseif (strtolower(trim($category)) === "negative") {
                $result = 0;
            } elseif (strtolower(trim($category)) === "send-mail") {
                $result = 2;
            } else {
                $result = "ok"; // unknown case
            }
        } else {
            return 100;
        }
    }

    /**
     * Normalise a classification value returned by Gemini (sentiment, category,
     * action_required, mass_mail) so the switch statements keep matching
     * lowercase labels regardless of how the model cased them.
     */
    private function aiFieldValue($value)
    {
        return is_string($value) ? strtolower(trim($value)) : null;
    }

    /**
     * The account whose sentiment vocabulary applies to the signed-in user.
     *
     * Employees read their admin's labels, so both see the same filters and the
     * same numbers. Null when nobody is signed in, which falls the model back
     * to the built-in defaults.
     */
    private function sentimentOwnerId(): ?int
    {
        return Sentiment::ownerIdFor(Auth::id());
    }

    /** The account's active sentiment labels, in display order. */
    private function sentimentVocabulary()
    {
        return Sentiment::activeFor($this->sentimentOwnerId());
    }

    /** The sentiment block of the classifier prompt, built from those labels. */
    private function sentimentPromptSection(): string
    {
        return Sentiment::promptSection($this->sentimentOwnerId(), null, 8);
    }

    /** The label named in the prompt's worked example. */
    private function sentimentFallbackCode(): string
    {
        return Sentiment::fallbackCode($this->sentimentOwnerId());
    }

    /**
     * Everything the toolbar and the mail list need to render one chip per
     * sentiment, keyed by the filter slug that opens it.
     *
     * Also keyed by legacy_code and by code in the lookup arrays, because the
     * mail list has only the stored word and the stored number to work from.
     */
    private function sentimentChipDefinitions(): array
    {
        $defs = [];

        foreach ($this->sentimentVocabulary() as $sentiment) {
            $defs[$sentiment->filter_slug] = [
                'code' => $sentiment->code,
                'label' => $sentiment->name,
                'slug' => $sentiment->filter_slug,
                'colour' => $sentiment->colour,
                'hex' => $sentiment->hex(),
                'pill' => $sentiment->pillClass(),
                'legacy_code' => (int) $sentiment->legacy_code,
            ];
        }

        return $defs;
    }

    /**
     * Mail count per sentiment, keyed by filter slug.
     *
     * One grouped query rather than one per label, because the vocabulary is
     * now open-ended. The predicate matches the sentiment branch of
     * filterMails() exactly, so a chip reading 917 opens a list of 917 mails.
     *
     * @param  string|null  $excludeOwnEmail  when set, mail the user sent is left out
     * @param  bool  $excludeSpamLabel  apply the provider spam-label clause
     */
    private function sentimentCounts($userId, ?string $excludeOwnEmail = null, bool $excludeSpamLabel = true): array
    {
        $query = Message::where('user_id', $userId)
            ->where('is_promotion', '0')
            ->where('message_status', 0);

        if ($excludeOwnEmail) {
            $query->where('sender_email', '!=', $excludeOwnEmail);
        }

        if ($excludeSpamLabel) {
            $query->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%']);
        }

        $rows = $query->selectRaw('is_spam, COUNT(DISTINCT email_id) as total')
            ->groupBy('is_spam')
            ->pluck('total', 'is_spam');

        // Keyed by slug and zero-filled, so a label with no mail still gets a
        // chip and the sum is the sentiment total.
        $counts = [];
        foreach ($this->sentimentVocabulary() as $sentiment) {
            $counts[$sentiment->filter_slug] = (int) ($rows[(string) $sentiment->legacy_code] ?? 0);
        }

        return $counts;
    }

    /**
     * Apply one sentiment's filter to a mail listing, or return false when the
     * requested type is not a sentiment slug.
     *
     * Kept beside sentimentCounts() because the two predicates have to agree.
     */
    private function applySentimentFilter($query, string $type, bool $excludeSpamLabel = true)
    {
        $sentiment = $this->sentimentVocabulary()->firstWhere('filter_slug', $type);

        if (!$sentiment) {
            return false;
        }

        $query->where('is_spam', $sentiment->legacy_code)
            ->where('is_promotion', '=', '0')
            ->where('message_status', 0);

        if ($excludeSpamLabel) {
            $query->whereRaw('LOWER(label_ids) NOT LIKE ?', ['%spam%']);
        }

        return $sentiment->name . ' Mail';
    }

    /**
     * Clean the per-mail summary returned by the same classification prompt.
     * Casing is preserved because this is displayed to the user.
     */
    private function aiSummaryValue($value)
    {
        if (!is_string($value)) {
            return null;
        }

        $summary = trim(preg_replace('/\s+/u', ' ', strip_tags($value)));

        // The model is told to emit this only for an empty body; treat it as
        // "no usable summary" so the caller can fall back to the mail itself.
        $sentinel = strtolower(rtrim($summary, " .!"));
        if ($summary === '' || $sentinel === 'no summary available' || $sentinel === 'no summary') {
            return null;
        }

        return mb_substr($summary, 0, 1000);
    }


    public function mail_conn($email, $app_pass)
    {
        $hostname = '{imap.gmail.com:993/imap/ssl}INBOX';

        try {
            // Try to connect to Gmail IMAP
            $inbox = imap_open($hostname, $email, $app_pass);

            if (!$inbox) {
                // If connection fails, get the error message
                $errorMessage = imap_last_error();
                return [
                    'success' => false,
                    'message' => "IMAP Connection Failed: " . $errorMessage
                ];
            }

            return [
                'success' => true,
                'message' => "IMAP Connection Established Successfully!",
                "inbox" => $inbox
            ];
        } catch (\Exception $e) {
            // Handle any unexpected exceptions
            return [
                'success' => false,
                'message' => "Please send valid email or app password Exception: " . $e->getMessage()
            ];
        }
    }

    public function close_mail($inbox)
    {
        imap_close($inbox);
    }
}
