<?php

namespace App\Http\Controllers\Api\Sales;

use App\Http\Controllers\Controller;

use App\Models\Invoice;

use App\Models\InvoiceItem;

use App\Models\Customers;
use App\Models\TourPackage;

use App\Models\User;
use App\Models\Dsr;
use App\Models\Mice;

use App\Mail\InvoiceMail;
use App\Service\StaticMaster;

use App\Models\SentMail;
use App\Models\Transaction;

use Illuminate\Support\Facades\Mail;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Redirect;

use Illuminate\Support\Facades\Http;

use App\Service\StockEntryService;

use App\Service\SequenceService;

use App\Service\AccountsTransactionService;

use PDF;
use Auth;
use DB;
use Log;
use Carbon\Carbon;

class InvoiceController extends Controller{

    public function list(Request $request) {

        $user=Auth::user();
         // Validate Item

         $validator=validator($request->all(),[

            'fy'=>'required',
            // 'warehouse_id'=>'required'

        ]);

        if ($validator->fails()) { 

            return [

                'success' => false, 

                'message' => $validator->errors()->first()

            ];

        } else {

            $invoices= Invoice::with("items","customer","items.item:id,name")
                ->where('is_disabled',0)
                // ->where('warehouse_id',$request['warehouse_id'])
                ->where('fy',$request['fy']);


            if ($request['status']!='' && isset($request['status'])) {
                $invoices=$invoices->where('status',$request['status']);
            }

            if($request['statuses']!='' && isset($request['statuses'])){
                $invoices=$invoices->whereIn('status',$request['statuses']);
            }

            // for pending credit note invoices
            // sending is_credit_note_close=1 from frontend
            if($request['is_credit_note_close']==1 && isset($request['is_credit_note_close'])){
                $invoices=$invoices->where('is_credit_note_close',0);
            }

            if ($request['is_invoice']!='') {
                $invoices=$invoices->where('is_invoice',$request['is_invoice']);
            }

            if ($request['customer_id']!='' && $request['customer_id']!=null && isset($request['customer_id'])) {
                $invoices=$invoices->where('customer_id',$request['customer_id']);
            }

            if($request['search']!=null && $request['search']!=''){

                // $searchTerm = $request['search'];
                $invoices = $invoices->where(function ($query) use ($request) {
                    $query->where('invoice_id', 'LIKE', '%' . $request['search'] . '%')
                        ->orWhere('reference_no', 'LIKE', '%' . $request['search'] . '%')
                        ->orWhere('display_name', 'LIKE', '%' . $request['search'] . '%')
                        ->orWhere('customer_type', 'LIKE', '%' . $request['search'] . '%')
                        // ->orWhere('mobile_no', 'LIKE', '%' . $request['search'] . '%')
                        ->orWhere('phone', 'LIKE', '%' . $request['search'] . '%')
                        ->orWhere('email', 'LIKE', '%' . $request['search'] . '%');
                });

            }

                // get alphabetically data by customer_name

            if ($request['customer_name']!='' && isset($request['customer_name'])) {

                $invoices=$invoices->orderBy('customer_name');

            }
                // get custom_date data by transaction_date

            if ($request['expiry_date']==1 && isset($request['expiry_date'])) {

                $invoices = $invoices->whereDate('due_date','<', $request['expiry_date']);

            }

            if ($request['custom_date']!='' && isset($request['custom_date'])) {

                $customDate = $request->custom_date;

                $invoices = $invoices->whereDate('transaction_date', $customDate);

            }

                // get fromDate toDate data by created_at

            if ($request['from_date']!='' && isset($request['to_date'])) {

                $fromDate = $request->from_date;

                $toDate = $request->to_date;

                // 'fromDate' and 'toDate'

                $invoices = $invoices->whereBetween('transaction_date', [$fromDate, $toDate]);

            }

            $count=$invoices->count();

            if(isset($request['sort_by']) && $request['sort_by']!='' && $request['sort_by']!=null){
                
                $sort_order=$request['sort_order']==1?'asc':'desc';

                $invoices = $invoices->orderby($request['sort_by'],$sort_order);

            }else{
                $invoices = $invoices->orderby('id','desc');
            }

            $invoices=$invoices->skip($request['noofrec']*($request['currentpage']-1))->take($request['noofrec']??100)
                            ->get();

            $response=[

                'message'=>'Invoice List Fetched Successfully',

                'invoice'=>$invoices,

                'count'=>$count,

                'success'=>true

            ];

            return response()->json($response);

        }

    }

    public function details(Request $request)
    {

        $user=Auth::user();
        // Validate Item

        $validator=validator($request->all(),[
            'id'=>'required'
        ]);

        if ($validator->fails()) { 

            return [
                'success' => false, 
                'message' => $validator->errors()->first()
            ];

        } else {

            $invoice = Invoice::where('id',$request['id'])

                // ->where('organisation_id',$user['active_organisation'])
                ->with('items','customer','customer.address','customer.address.city:id,name',
                    'customer.address.country:id,name','customer.address.state:id,name','items.item','activity',
                    'customer.contact_person')

                ->first();

                if ($invoice['items']->count() > 0) {
                    foreach ($invoice['items'] as $key => $item) {
                        if (!empty($item->service_data)) {
                            $service_data = $item->service_data; // already array

                            // Getting Guests 
                            $guestIds = explode(',', $service_data['guest_ids'] ?? '');
                            $service_data['guests'] = User::whereIn('id', $guestIds)->get();

                            // Laravel will auto re-encode to JSON when saving
                            $item->service_data = $service_data;
                            $item->save();
                        }
                    }
                }

            $transaction=Transaction::where('transaction_type',StaticMaster::$SALE_TRANSACTION_TYPE)
                ->where('transaction_id',$request['id'])
                ->where('is_disabled',0)
                ->with('account:id,account_name,account_code')
                ->get();

            $response=[
                'Invoice'=>$invoice,
                'transaction'=>$transaction,
                'message'=>'Details Fetched Successfully'
            ];

            return response()->json($response);

        }
    }

    public function pdf(){

        $pdf = PDF::loadView('view');

        // return $pdf->download('sample.pdf');

        return $pdf->stream('invoice.pdf');
    }

    public function delete(Request $request){

        // Validate Item

        $validator=validator($request->all(),[
            'id'=>'required'
        ]);

        if ($validator->fails()) { 

            return [
                'success' => false, 
                'message' => $validator->errors()->first()
            ];

        } else {

            try{

                $invoice = Invoice::findOrFail($request['id']);

            } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {

                // Return error message in JSON if ID not found

                return response()->json(['message' => 'Invalid Id to update'], 404);

            }

            if($invoice['is_approved']==0){

                $invoice['is_disabled']=1;
                $invoice->update();

                $invoice_items=InvoiceItem::where('transaction_id',$invoice['id'])->get();

                foreach ($invoice_items as $value){

                    $value['is_disabled']=1;
                    $value->update();
                }

                $response=[

                    'success'=>true,

                    'message'=>'Invoice deleted Successfully'

                ];

            }else{

                $response=[

                    'success'=>false,

                    'message'=>'Invoice is Approved. You can\'t delete this invoice.'
                ];
            }
            return response()->json($response);

        }

    }

    public function send_mail(Request $request)
    {
        $user = Auth::user();

        // Validate Item
        $validator=validator($request->all(),[
            'id' => 'required',
            'to_email' => 'required|email', // Ensuring email is valid
            'subject' => 'required',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return [
                'success' => false,
                'message' => $validator->errors()->first(),
            ];
        }

        try {
            $invoice = Invoice::where('id', $request['id'])
                // ->where('organisation_id', $user['active_organisation'])
                ->with('items', 'items.item', 'customer')->firstOrFail();

        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return response()->json(['success'=>false,'message' => 'Invalid ID found'], 404);
        }

        $email = $request['to_email'];

        if ($email) {

            $obj = [
                'to_email' => $email,
                'subject' => $request['subject'],
                'body' => $request['body'],
                'attachments' => $request['upload_documents'],
                'module_id' => $request['id'],
                'module_type' => 'invoice',
            ];

            $sent_email = SentMail::create($obj);

            $data['email'] = $email;
            $data['title'] = 'Invoice Details';
            $data['invoice'] = $invoice;
            $data['mail_data'] = $sent_email;

            // Decode attachments once
            $attachments = json_decode($request['upload_documents'], true);

            Mail::send('invoice.invoice', ['data' => $data], function ($message) use ($data, $attachments, $request) {
                $message->to($data['email'])->subject($request['subject']);

                foreach ($attachments as $attachment) {
                    $url = $attachment['url'];
                    $name = $attachment['name'];

                    try {
                        // $url = urldecode($url);

                        // Validate URL format
                        if (!filter_var($url, FILTER_VALIDATE_URL)) {
                            Log::error("Invalid URL format: $url");
                            continue;
                        }

                        // Fetch the file content
                        $response = Http::get($url);

                        if ($response->successful()) {

                            $fileContent = $response->body();
                            $contentType = $response->header('Content-Type');

                            // Sanitize the filename
                            $fileName = basename(parse_url($url, PHP_URL_PATH));
                            $fileName = $fileName ?: 'attachment.' . mime2ext($contentType);

                            // Ensure the filename is safe for attachments
                            $fileName = preg_replace('/[^a-zA-Z0-9\-_\.]/', '_', $fileName);

                            // Attach the file content to the email
                            $message->attachData($fileContent, $fileName, [
                                'mime' => $contentType,
                            ]);

                            Log::info("File Attached");

                        } else {
                            Log::error("Failed to fetch file from URL: $url", ['status' => $response->status()]);
                        }
                    } catch (\Exception $e) {

                        Log::error("Exception occurred while processing URL: $url", ['exception' => $e->getMessage()]);
                    }
                }
            });

            // Mark invoice as mail sent
            $invoice->is_mail_sent = 1;
            $invoice->update();

            return response()->json([
                'success' => true,
                'message' => 'Invoice sent successfully',
            ]);
        } else {
            return response()->json([
                'success' => false,
                'message' => 'Customer Email does not exist',
            ]);
        }
    }

/**
 * Convert MIME type to file extension
 * 
 * @param string $mimeType
 * @return string
 */
    function mime2ext($mimeType)
    {
        $mimeTypes = [
            'image/jpeg' => 'jpg',
            'image/png' => 'png',
            'image/jfif' => 'jfif',   // For JFIF specifically
            'application/pdf' => 'pdf',
            'image/gif' => 'gif',
            'text/plain' => 'txt',
            // Add more MIME types as needed
        ];

        return $mimeTypes[$mimeType] ?? 'bin'; // Default to 'bin' if MIME type is unknown
    }

    public function statusInvoice(Request $request){
        // Validate Item
        $status_change='';
        $today_date = Carbon::now()->format('Y-m-d');

        $validator=validator($request->all(),[
            'id'=>'required',
            'status'=>'required'
        ]);

        if ($validator->fails()) { 

            return [
                'success' => false, 
                'message' => $validator->errors()->first()
            ];

        } else {

            $module='invoice';

            $transaction = Invoice::findOrFail($request->id);

            $transaction['status']=$request['status'];

            if($transaction['due_date']==null){

                $date = Carbon::now()->addDays($transaction['payment_term_day'])->format('Y-m-d');
                $transaction['due_date']=$date;
            }

            // Status Approving will take into stock and accounts entry
            if($request['status']==1){

                $entity='Invoice';

                // When the invoice is Approved
                $status_change='Approved';
                $transaction['is_approved']=1;

                // Setting Approving Date as today date
                $transaction['approved_date']=$today_date;

                // Saving Stock Entries
                $stockEntryService = new StockEntryService;
                $stockEntryService->saveStockEntries($transaction,$entity,2);

                // Saving Accounts Entries
                $accountsEntryService = new AccountsTransactionService;
                $accountsEntryService->sale_accounts_transaction($transaction);
                // $accounts_entry=$this->updateAccountsTransactions($transaction);


                //This is only for DSR and MICE
                if($transaction['is_dsr']==1){
                    $dsr=Dsr::where('dsr_no',$transaction['reference_no'])->update([
                        'is_invoiced'=>2]);
                }
                if($transaction['is_mice']==1){
                    $mice=Mice::where('mice_no',$transaction['reference_no'])->update([
                        'is_invoiced'=>2]);
                }

                // Update Sequence Number on approve
                $sequence=new SequenceService;
                $sequence->updateSequence($module);
            }

            // Declined Status
            if($request['status']==2){

                $status_change='Declined';
                $transaction['is_approved']=0;

                if($transaction['is_dsr']==1){

                    $dsr=Dsr::where('dsr_no',$transaction['reference_no'])->update([
                        'is_invoiced'=>0 , 
                        'is_accounting'=>0,
                        'total_gross_amount'=>0,
                        'total_tax_amount'=>0,
                        'total_final_amount'=>0,
                        'total_retain_amount'=>0
                    ]);

                    // $transaction['is_disabled']=1;   // delete the invoice

                    // $sequenceService = new SequenceService;
                    // $sequenceService->deleteSequence('invoice');
                }
                if($transaction['is_mice']==1){

                    $mice=Mice::where('mice_no',$transaction['reference_no'])->update([
                        'is_invoiced'=>0, 
                        'is_accounting'=>0,
                        'total_gross_amount'=>0,
                        'total_tax_amount'=>0,
                        'total_final_amount'=>0,
                        'total_retain_amount'=>0
                    ]);

                    // $transaction['is_disabled']=1;   // delete the invoice

                    // $sequenceService = new SequenceService;
                    // $sequenceService->deleteSequence('invoice');
                }
            }

            // Status Draft
            if($request['status']==0){

                $status_change='Draft';
            }

            // Updating Above Status
            $transaction->update();  

            $response=[ 
                'success'=>true,
                'message'=>'Invoice '.$status_change.' Updated Successfully'
            ];

            return response()->json($response);

        }
    }


    // pending invoices against Customer
    public function pendingInvoice(Request $request){
        $user = Auth::user();

        $validator=validator($request->all(),[
            'fy'=>'required',
            // 'warehouse_id'=>'required',
            'customer_id'=>'required'
        ]);

        if ($validator->fails()) { 

            return [
                'success' => false, 
                'message' => $validator->errors()->first()
            ];

        } else {

            $invoice=invoice::whereRaw('amount_paid < total')
                ->where('is_approved',1)
                ->where('is_disabled',0)
                ->where('is_accounting',1);
                // ->where('fy',$request['fy']);
                // ->where('total','>','amount_paid')
                // ->where('warehouse_id',$request['warehouse_id'])
                // ->where('organisation_id',$user['active_organisation']);

            if(isset($request['customer_id']) && $request['customer_id']!='' && $request['customer_id']!=null){
                $invoice=$invoice->where('customer_id',$request['customer_id']);
            }

            if(isset($request['invoice_no']) && $request['invoice_no']!=''){
                $invoice=$invoice->where('invoice_id',$request['invoice_no']);
            }

            // $total_amount=$invoice->sum('total-amount_paid');

            $unpaid_amount = $invoice->get()->sum(function($inv) {
                return $inv->total - $inv->amount_paid;
            });

            $invoice=$invoice->get();

            $customer=User::where('id',$request['customer_id'])
                ->with('billing_address','shipping_address','address','bank_details')
                ->first();

            $response=[
                'success'=>true,
                'unpaid_amount'=>$unpaid_amount,
                'message'=>'Total pending Invoice retrieved successfully',
                'invoices'=>$invoice,
                'customer'=>$customer
            ];

            return response()->json($response);
        }

    }

    public function mail_status(Request $request){
        $validator=validator($request->all(),[

            'invoice_id'=>'required',
            // 'is_mail_sent'=>'required|integer'

        ]);

        if ($validator->fails()) { 

            return [

                'success' => false, 

                'message' => $validator->errors()->first()

            ];

        } else {

            try{

                $transaction = Invoice::findOrFail($request->invoice_id);

                $transaction['is_mail_sent']=1;

                $transaction->update();  

            } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {

                // Return error message in JSON if ID not found
                return response()->json(['message' => 'Invalid Id to update '], 404);
            }
        }

        $response=[
            'success'=>true,
            'message'=>'Mail sent Successfully'
        ];

        return response()->json($response);
    }
}