<?php

namespace App\Services;

use App\Http\Resources\SupplierResource;
use App\Models\Company;
use App\Models\Country;
use App\Models\Department;
use App\Models\District;
use App\Models\PriceList;
use App\Models\Province;
use App\Models\Salesman;
use App\Models\Segment;
use App\Models\Supplier;
use App\Models\SupplierContact;
use App\Models\ClientAddress;
use App\Models\WayToPay;
use App\Traits\HasResponse;
use Illuminate\Support\Facades\DB;
use Maatwebsite\Excel\Facades\Excel;
use App\Imports\ClientsDataImport;
use App\Imports\ClientsAddressDataImport;

/**
 * Class SupplierService
 * @package App\Services
 */
class SupplierService
{
    use HasResponse;

    public function list($params, $withPagination)
    {
        $suppliers = Supplier::supplierFilters()->orderBy('id', 'desc');

        $suppliers = !empty($withPagination)
            ? $suppliers->paginate($withPagination['perPage'], page: $withPagination['page'])
            : $suppliers->get();

        $paginationTotal = null;
        if (!empty($withPagination)) $paginationTotal = $suppliers->total();

        $suppliers = SupplierResource::collection($suppliers->load([
            'wayToPay',
            'segment',
            'country',
            'department',
            'province',
            'district',
            'company',
            'addresses.country',
            'addresses.department',
            'addresses.province',
            'addresses.district',
            'salesman',
            'businessArea',
        ]));

        if (request()->boolean('accountReceivable')) {
            $suppliers = $suppliers->collection->sortByDesc('accounts_receivable_expired')->values();
        }

        return $this->successPaginationResponse('Lectura exitosa.', $paginationTotal, $suppliers);
    }

    public function register($params)
    {
        DB::beginTransaction();
        try {
            #Validar duplicidad de rut
            $rut = Supplier::where('rut', $params['rut'])->active()->first();
            if ($rut) return $this->errorResponse('Ya existe un registro con el rut ingresado.', 400);

            $supplier = Supplier::create([
                'rut'           => $params['rut'],
                'name_rz'       => $params['name_rz'],
                'fantasy_name'  => $params['fantasy_name'] ?? null,
                'web'           => $params['web'] ?? null,
                'giro'          => $params['giro'] ?? null,
                'email'         => $params['email'],
                'phone'         => $params['phone'],
                'fax'           => $params['fax'] ?? null,
                'type'          => $params['type'],
                'legal_nature'  => $params['legal_nature'],
                'idcompany'     => $params['idcompany'],
                'idsalesman'    => $params['idsalesman'] ?? null,
                'idbussines_area' => $params['idbussines_area'] ?? null,
                'idwaytopay'      => $params['idwaytopay'] ?? null
            ]);
            $supplier->save();

            if (count($params['contacts']) > 0) {
                $contacts = [];
                foreach ($params['contacts'] as $contact) {
                    $contacts[] = [
                        'rut' => $contact['rut'],
                        'name' => $contact['name'],
                        'position' => $contact['charge'],
                        'email' => $contact['email'] ?? null,
                        'phone' => $contact['phone'] ?? null,
                        'idsupplier' => $supplier->id,
                        'idcompany' => $supplier->idcompany,
                    ];
                }
                SupplierContact::insert($contacts);
            }

            if (count($params['addresses']) > 0) {

                if (count($params['addresses']) > 0) {
                    $addresses = array_map(function ($address) use ($supplier) {
                        $address['idclient']  = $supplier->id;
                        $address['idcompany'] = $supplier->idcompany;

                        if (!isset($address['idprovince']) && isset($address['iddistrict'])) {
                            $address['idprovince'] = District::where('id', $address['iddistrict'])->value('idprovince');
                        }

                        if (!isset($address['iddepartment']) && isset($address['idprovince'])) {
                            $address['iddepartment'] = Province::where('id', $address['idprovince'])->value('iddepartment');
                        }

                        if (!isset($address['idcountry']) && isset($address['iddepartment'])) {
                            $address['idcountry'] = Department::where('id', $address['iddepartment'])->value('idcountry');
                        }

                        return $address;
                    }, $params['addresses']);

                    ClientAddress::insert($addresses);
                }
            }

            DB::commit();
            return $this->successResponse('Proveedor/cliente registrado satisfactoriamente.', $supplier);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la creación de un proveedor/cliente.', $th->getMessage());
        }
    }

    public function importExcel($params)
    {
        DB::beginTransaction();
        try {
            $file = $params['clients_import'];

            Excel::import(new ClientsDataImport($params), $file);

            DB::commit();
            return $this->successResponse('OK', 'Datos importados correctamente.');
        } catch (\throwable $th) {
            throw $th;
            return $this->externalError('durante la importación de Clientes', $th->getMessage());
        }
    }

    public function importAddressExcel($params)
    {
        DB::beginTransaction();
        try {
            $file = $params['excel_import'];

            Excel::import(new ClientsAddressDataImport($params), $file);

            DB::commit();
            return $this->successResponse('OK', 'Datos importados correctamente.');
        } catch (\throwable $th) {
            throw $th;
            return $this->externalError('durante la importación de direcciones de Clientes', $th->getMessage());
        }
    }

    public function update($id, $params)
    {
        DB::beginTransaction();
        try {
            #Validar proveedor/cliente
            $supplier = Supplier::activeForId($id)->first();
            if (!$supplier) return $this->errorResponse('Proveedor/cliente no válido.', 400);

            if (isset($params['rut'])) {
                #Validar duplicidad de rut
                $rut = Supplier::where('id', '!=', $id)->where('rut', $params['rut'])->active()->first();
                if ($rut) return $this->errorResponse('Ya existe un registro con el rut ingresado.', 400);
            }

            $supplier->update($params);
            $supplier->save();

            if (isset($params['contacts'])) {
                $idContact = [];
                $newContacts = [];
                foreach ($params['contacts'] as $contact) {
                    if ($contact['id'] != null) {
                        $idContact[] = (int) $contact['id'];
                    } else {
                        $newContacts[] = [
                            'rut' => $contact['rut'],
                            'name' => $contact['name'],
                            'position' => $contact['charge'],
                            'email' => $contact['email'] ?? null,
                            'phone' => $contact['phone'] ?? null,
                            'idsupplier' => $supplier->id,
                            'idcompany' => $supplier->idcompany,
                        ];
                    }
                }

                #Borrar contactos
                SupplierContact::whereNotIn('id', $idContact)->where('idsupplier', $supplier->id)->active()->update(['status' => 2]);

                #Guardar contactos
                if (!empty($newContacts)) {
                    SupplierContact::insert($newContacts);
                }
            }

            if (isset($params['addresses'])) {
                $idAddresses = [];
                $newAddresses = [];

                foreach ($params['addresses'] as $clientAddress) {
                    if ($clientAddress['id'] != null) {
                        $idAddresses[] = (int) $clientAddress['id'];
                    } else {
                        $newAddresses[] = $clientAddress;
                    }
                }

                ClientAddress::whereNotIn('id', $idAddresses)->where('idclient', $supplier->id)->active()->update(['status' => 2]);
                if (!empty($newAddresses)) {
                    $addresses = array_map(function ($address) use ($supplier) {
                        $address['idclient'] = $supplier->id;

                        if (!isset($address['idprovince']) && isset($address['iddistrict'])) {
                            $address['idprovince'] = District::where('id', $address['iddistrict'])->value('idprovince');
                        }

                        if (!isset($address['iddepartment']) && isset($address['idprovince'])) {
                            $address['iddepartment'] = Province::where('id', $address['idprovince'])->value('iddepartment');
                        }

                        if (!isset($address['idcountry']) && isset($address['iddepartment'])) {
                            $address['idcountry'] = Department::where('id', $address['iddepartment'])->value('idcountry');
                        }

                        return $address;
                    }, $newAddresses);
                    ClientAddress::insert($addresses);
                }
            }

            DB::commit();
            return $this->successResponse('Proveedor/cliente actualizado satisfactoriamente.', $supplier);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la edición de un proveedor/cliente.', $th->getMessage());
        }
    }

    public function delete($id)
    {
        try {
            #Validar proveedor/cliente
            $supplier = Supplier::activeForId($id)->first();
            if (!$supplier) return $this->errorResponse('Proveedor/cliente no válido.', 400);

            $supplier->status = 2;
            $supplier->save();

            SupplierContact::where('idsupplier', $supplier->id)->update(['status' => 2]);
            SupplierContact::where('idclient', $supplier->id)->update(['status' => 2]);

            DB::commit();
            return $this->successResponse('Proveedor/cliente actualizado satisfactoriamente.', $supplier);
        } catch (\Throwable $th) {
            DB::rollBack();
            return $this->externalError('durante la edición de un proveedor/cliente.', $th->getMessage());
        }
    }
}
