<?php

namespace App\Http\Controllers;

use App\Models\BillingService;
use App\Models\MiscellaneousCharge;
use App\Models\User;
use App\Services\XeroService;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use DateTime;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Storage;

class BillingScriptController extends Controller
{

    /**
     * Billing
     */
    public function billing()
    {
        $date_end_search = time() + 1209600;
        $date_end_search = date('Y-m-d', $date_end_search);
        $currentDate = date('Y-m-d');
        $charges = MiscellaneousCharge::where('date_invoice', $currentDate)->where('invoiced', 0)->get();
        $services_to_be_billed = [];
        $keyCharge = 0;

        foreach ($charges as $key => $charge) {
            $xero = new XeroService();
            try{
                $contact = $xero->getXeroContact($charge->customer->xero_contact_id);
            }catch (\Exception $e){
                Log::info('Customer not found '.$charge->customer_id.'. Billing Script');
                continue;
            }
            $mainContactName = $contact['Name'];
            if( !$contact['EmailAddress']){
                Log::info('Xero customer '.$charge->customer->xero_name.' has no email address record');
            }else {
                $persons = (array)$contact['ContactPersons'];
                $ContactPersons = [];
                foreach ($persons as $person) {
                    if( isset($person['IncludeInEmails']) && $person['IncludeInEmails'] == 'true') {
                        $ContactPersons[] = $person['EmailAddress'];
                    }
                }
                $services_to_be_billed[$charge->customer->xero_contact_id]['services'][$keyCharge]['type'] = 'charge';
                $services_to_be_billed[$charge->customer->xero_contact_id]['services'][$keyCharge]['service'] = $charge;
                $services_to_be_billed[$charge->customer->xero_contact_id]['name'] = $mainContactName;
                $services_to_be_billed[$charge->customer->xero_contact_id]['email'] = $contact['EmailAddress'];
                $services_to_be_billed[$charge->customer->xero_contact_id]['contactPersons'] = $ContactPersons;
                $keyCharge++;
            }
        }

        $services = BillingService::where('do_not_bill', 0)
            ->where('next_billed', '<', $date_end_search)
            ->where('canseled_date', NULL)
            ->where('fee', '!=', 0)
            ->get();

        foreach ($services as $key => $service) {
            $xero = new XeroService();
            try{
                $contact = $xero->getXeroContact($service->customer->xero_contact_id);
            }catch (\Exception $e){
                Log::info('Customer not found '.$service->customer_id.'. Billing Script');
                continue;
            }
            $mainContactName = $contact['Name'];

            if( !$contact['EmailAddress']){
                Log::info('Xero customer '.$service->customer->xero_name.' has no email address record');
            }else {
                $persons = (array)$contact['ContactPersons'];
                $ContactPersons = [];
                foreach ($persons as $person) {
                    if( isset($person['IncludeInEmails']) && $person['IncludeInEmails'] == 'true') {
                        $ContactPersons[] = $person['EmailAddress'];
                    }
                }
                $services_to_be_billed[$service->customer->xero_contact_id]['services'][$keyCharge]['type'] = 'service';
                $services_to_be_billed[$service->customer->xero_contact_id]['services'][$keyCharge]['service'] = $service;
                $services_to_be_billed[$service->customer->xero_contact_id]['name'] = $mainContactName;
                $services_to_be_billed[$service->customer->xero_contact_id]['email'] = $contact['EmailAddress'];
                $services_to_be_billed[$service->customer->xero_contact_id]['contactPersons'] = $ContactPersons;
                $keyCharge++;
            }
        }

        foreach ($services_to_be_billed as $xero_contact_id => $services) {

            $email = $services['email'];
            $name = $services['name'];

            if (strpos($name, '(DD)') !== false) {
                $directDebit = true;
                $invoiceTheme = 'e75a59cf-e4e5-4cae-9fc5-894e069b6b50';
            } else {
                $invoiceTheme = 'ac3dabbf-0f83-472e-be00-54f211e86a03';
                $directDebit = false;
            }

            $lineItems = [];
            $total = 0;
            foreach ($services['services'] as $key => $service) {

                if( $service['type'] == 'service' ) {
                    $service = $service['service'];

                    $next_billedObject = DateTime::createFromFormat('Y-m-d', $service->next_billed);
                    if( $service->renew == 3 ) {
                        $next_billedObject->modify('+12 month');
                    } elseif( $service->renew == 2 ) {
                        $next_billedObject->modify('+3 month');
                    } elseif ( $service->renew == 1 ) {
                        $next_billedObject->modify('+1 month');
                    }

                    $total += $service->fee;
                    $last_billed = $service->next_billed;

                    $last_billedDateObject = DateTime::createFromFormat('Y-m-d', $last_billed);

                    $last_billed_to_description = $last_billedDateObject->format('d/m/Y');

                    $next_billedObject = DateTime::createFromFormat('Y-m-d', $service->next_billed);
                    if( $service->renew == 3 ) {
                        $next_billedObject->modify('+12 month');
                    } elseif( $service->renew == 2 ) {
                        $next_billedObject->modify('+3 month');
                    } elseif ( $service->renew == 1 ) {
                        $next_billedObject->modify('+1 month');
                    }
                    $next_billedObject->modify('-1 days');
                    $next_billedObject->format('Y-m-d');

                    $next_billed_to_description = $next_billedObject->format('d/m/Y');

                    $serviceType = substr($service->service_ref, 0, 2);

                    $description = '';
                    if( $serviceType == 'HS' ) {
                        $description.= 'Our reference '.$service->service_ref."\r\n\r\n";
                        $description.= 'Website Hosting Services ('.$service->description.')'."\r\n";
                        $description.= $last_billed_to_description. ' to '.$next_billed_to_description;

                        $AccountCode = 4004;
                    } elseif( $serviceType == 'ES' ) {
                        $description.= 'Our reference '.$service->service_ref."\r\n\r\n";
                        $description.= 'Email Services ('.$service->description.')'."\r\n";
                        $description.= $last_billed_to_description. ' to '.$next_billed_to_description;
                        $AccountCode = 4010;
                    } elseif( $serviceType == 'AS' ) {
                        $description.= 'Our reference '.$service->service_ref."\r\n\r\n";
                        $description.= $service->description."\r\n";
                        $description.= $last_billed_to_description. ' to '.$next_billed_to_description;
                        $AccountCode = 4011;
                    }

                    $lineItems[] = [
                        'Description' => htmlspecialchars($description, ENT_XML1, 'UTF-8'),
                        'AccountCode' => $AccountCode,
                        'LineAmount' => $service->fee,
                        'TaxType' => $service->customer->tax_type,
                    ];

                    $invoice_rule_Object = DateTime::createFromFormat('Y-m-d', $date_end_search);

                    while ($next_billedObject < $invoice_rule_Object):
                        $description = '';
                        $last_billedDateObject = DateTime::createFromFormat('d/m/Y', $next_billed_to_description);
                        $last_billedDateObject->modify('+1 days');
                        $last_billed_to_description = $last_billedDateObject->format('d/m/Y');

                        if( $service->renew == 3 ) {
                            $next_billedObject->modify('+12 month');
                        } elseif( $service->renew == 2 ) {
                            $next_billedObject->modify('+3 month');
                        } elseif ( $service->renew == 1 ) {
                            $next_billedObject->modify('+1 month');
                        }
                        $next_billedObject->modify('-1 days');
                        $next_billed_to_description = $next_billedObject->format('d/m/Y');
                        if( $serviceType == 'HS' ) {
                            $description.= 'Our reference '.$service->service_ref."\r\n\r\n";
                            $description.= 'Website Hosting Services ('.$service->description.')'."\r\n";
                            $description.= $last_billed_to_description. ' to '.$next_billed_to_description;
                            $AccountCode = 4004;
                        } elseif( $serviceType == 'ES' ) {
                            $description.= 'Our reference '.$service->service_ref."\r\n\r\n";
                            $description.= 'Email Services ('.$service->description.')'."\r\n";
                            $description.= $last_billed_to_description. ' to '.$next_billed_to_description;
                            $AccountCode = 4010;
                        } elseif( $serviceType == 'AS' ) {
                            $description.= 'Our reference '.$service->service_ref."\r\n\r\n";
                            $description.= $service->description."\r\n";
                            $description.= $last_billed_to_description. ' to '.$next_billed_to_description;
                            $AccountCode = 4011;
                        }

                        $lineItems[] = [
                            'Description' => htmlspecialchars($description, ENT_XML1, 'UTF-8'),
                            'AccountCode' => $AccountCode,
                            'LineAmount' => $service->fee,
                            'TaxType' => $service->customer->tax_type,
                        ];

                        $total += $service->fee;
                    endwhile;

                    $vat = true;
                    if( $service->customer->tax_type != 'OUTPUT2' )  {
                        $vat = false;
                    }
                } elseif( $service['type'] == 'charge' ) {
                    $charge = $service['service'];
                    $lineItems[] = [
                        'Description' => htmlspecialchars($charge->description, ENT_XML1, 'UTF-8'),
                        'AccountCode' => '4015',
                        'LineAmount' => $charge->price,
                        'TaxType' => $charge->customer->tax_type,
                    ];
                    $total += $charge->price;
                    $vat = true;
                    if( $charge->customer->tax_type != 'OUTPUT2' )  {
                        $vat = false;
                    }
                }
            }

            $date_start = str_replace('+00:00', '', date(DATE_ATOM, time()));
            $date_end = time() + 1209600;
            $date_end = str_replace('+00:00', '', date(DATE_ATOM, $date_end));

            $invoice_data = [
                'Type' => 'ACCREC',
                'Contact' => [
                    'ContactID' => $xero_contact_id
                ],
                'Date' => $date_start,
                'DueDate' => $date_end,
                'Status' => 'AUTHORISED',
                'BrandingThemeID' => $invoiceTheme,
                'LineAmountTypes' => 'Exclusive',
                'LineItems' => $lineItems
            ];
            $user = User::first();
            $response = Http::withHeaders([
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
                'Xero-Tenant-Id' => $user->tenant_id,
                'Authorization' => 'Bearer ' . json_decode($user->xero_access_token, true)['access_token']
            ])->post('https://api.xero.com/api.xro/2.0/Invoices', $invoice_data);

            $invoice = json_decode($response->body());

            if(isset($invoice->ErrorNumber)){
                Log::info($invoice->Message . '. Billing script. ' . $xero_contact_id );
                continue;
            }
            $invoice = $invoice->Invoices[0];
            $new_invoice['new_invoice_id'] = $invoice->InvoiceID;
            $new_invoice['new_invoice_number'] = $invoice->InvoiceNumber;

            $response = Http::withHeaders([
                'Accept' => 'application/pdf',
                'Content-Type' => 'application/json',
                'Xero-Tenant-Id' => $user->tenant_id,
                'Authorization' => 'Bearer ' . json_decode($user->xero_access_token, true)['access_token']
            ])->get('https://api.xero.com/api.xro/2.0/Invoices/' . $new_invoice['new_invoice_number']);

            $pdf = $response->body();

            Storage::put('invoices/'.$new_invoice['new_invoice_number'].".pdf", $pdf);

            $customer_name = str_replace('(DD)', '', $name);
            $data['customer_name'] = $customer_name;
            $data['new_invoice_number'] = $new_invoice['new_invoice_number'];

            $data['total'] =$total;
            if( $vat == true ) {
                $vat = $total*0.2;
                $data['total'] =$total+$vat;
            }
            $data['direc_debit'] = $directDebit;
            $new_invoice['email'] = $email;

            Mail::send('emails.invoice', ['data' => $data], function ($message) use ($new_invoice, $services) {
                $message->from('hello@thinking.fish', 'Thinking Fish');
                $message->attach(storage_path('app/invoices/'.$new_invoice['new_invoice_number'].".pdf"));
                $message->bcc('pool@thinking.fish', 'Pool Thinking Fish');
                if( !empty($services['contactPersons'])  ) {
                    $message->cc($services['contactPersons']);
                }
                $message->to($new_invoice['email'])->subject('Invoice '.$new_invoice['new_invoice_number']);
            });

            foreach ($services['services'] as $key => $service) {

                if( $service['type'] == 'service' ) {
                    $service = $service['service'];
                    $last_billed = $service->next_billed;

                    $next_billedObject = DateTime::createFromFormat('Y-m-d', $service->next_billed);

                    while ($next_billedObject < $invoice_rule_Object):
                        if( $service->renew == 3 ) {
                            $next_billedObject->modify('+12 month');
                        } elseif( $service->renew == 2 ) {
                            $next_billedObject->modify('+3 month');
                        } elseif ( $service->renew == 1 ) {
                            $next_billedObject->modify('+1 month');
                        }
                        endwhile;

                        $next_billed = $next_billedObject->format('Y-m-d');

                        $serviceSave = BillingService::find($service->id);
                        $serviceSave->last_billed = $last_billed;
                        $serviceSave->next_billed = $next_billed;

                        $serviceSave->save();
                } elseif( $service['type'] == 'charge' ) {
                    $charge = $service['service'];
                    $charge->invoice = $new_invoice['new_invoice_number'];
                    $charge->invoiced = 1;
                    $charge->save();
                }
            }
            sleep (2);
        }
    }
}
