<?php

namespace App\Jobs;

use App\Components\Functions;
use App\Models\Action;
use App\Models\CollectSpend;
use App\Models\Contract;
use App\Models\ElectricWater;
use App\Models\Hostel;
use App\Models\HostelFee;
use App\Models\MoneyDetail;
use App\Models\MoneyInfo;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class ImportMoneyInfo implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */

    protected $filePath;
    protected $ownerId;
    protected $userId;
    protected $pusher;


    public function onConnection($connection)
    {
        $this->connection = 'redis';
        return $this;
    }

    public function __construct($filePath, $ownerId, $userId)
    {
        //
        $this->filePath = $filePath;
        $this->ownerId = $ownerId;
        $this->pusher = \PusherService::getClient();
        $this->userId = $userId;
    }

    public function pushErrorMessage($action, $message)
    {
        $errorMessages = cache()->get($action->id . '-error-messages');
        if (empty($errorMessages)) {
            $errorMessages = [];
        }
        $errorMessages[] = $message;
        cache()->put($action->id . '-error-messages', $errorMessages, 600);
    }

    public function triggerMessage()
    {
        $pusher = $this->pusher;
        $channelName = 'job-actions-' . $this->ownerId;
        $actions = Action::query()
            ->where('user_id', $this->ownerId)
            ->where('created_at', '>=', Carbon::now()->subDay(1)->startOfDay())
            ->whereNull('finished_at')
            ->get();
        $content = view('admin2.progress.actions', compact('actions'))->render();
        $pusher->trigger($channelName, 'action-content', $content);
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
        $cnt = 0;

        $pusher = $this->pusher;
        $filePath = $this->filePath;
        $ownerId = $this->ownerId;
        $channelName = 'job-actions-' . $this->ownerId;


        $action = Action::query()->updateOrCreate([
            'file' => $this->filePath,
            'type' => 'import-money-info',
        ], [
            'file' => $this->filePath,
            'user_id' => $this->userId,
            'type' => 'import-money-info',
        ]);
        cache()->forget($action->id . '-error-messages');
        cache()->forget($action->id . '-success-message');
        $items = \Excel::selectSheetsByIndex(0)->load($filePath, function ($reader) {
            $reader->noHeading()->takeRows(600);
        })->skip(1)->get();
        $number = count($items);
        
        
        if ($number == 0) {
            $number = 1;
        }


        cache()->put($action->id . '-progress', [
            'processed' => $cnt,
            'total' => 0,
            'percent' => round($cnt * 100 / $number)
        ], 600);
        $this->triggerMessage();

        if (!isset($items[0]) || !isset($items[1]) || !isset($items[2])) {
            $cnt = $number;

            $errorMessage = 'Dữ liệu không hợp lệ';
            $this->pushErrorMessage($action, $errorMessage);
            cache()->put($action->id . '-progress', [
                'processed' => $cnt,
                'total' => count($items),
                'percent' => round($cnt * 100 / (count($items)))
            ], 600);
            $this->triggerMessage();
            $action->finished_at = Carbon::now();
            $action->save();
            return;
        }
        $firstRow = $items[0];
        $secondRow = $items[1]; // Lấy 2 dòng đầu để xác nhận dịch vụ
        $thirdRow = $items[2]; // Lấy dòng 3 để lấy tên nhà, workaroud lỗi submit tên nhà sai

        unset($items[0]);
        unset($items[1]);

        for ($i = 1; $i <= 4; $i++) // Remove 4 cái cột đầu ko dùng đến
        {
            unset($firstRow[$i]);
            unset($secondRow[$i]);
        }

        $indexArr = [];

        if (!isset($thirdRow[1])) {
            $cnt = $number;

            $errorMessage = 'Vui lòng kiểm tra dữ liệu';
            $this->pushErrorMessage($action, $errorMessage);
            cache()->put($action->id . '-progress', [
                'processed' => $cnt,
                'total' => count($items),
                'percent' => round($cnt * 100 / (count($items)))
            ], 600);
            $this->triggerMessage();
            $action->finished_at = Carbon::now();
            $action->save();
            return;
        }


        $hostelName = $thirdRow[1];
        $hostel = Hostel::query()
            ->where('name', trim($hostelName))
            ->where('owner_id', $ownerId)
            ->first();


        if (!$hostel) {
            $cnt = $number;
            $errorMessage = 'Không tìm thấy nhà trọ';
            $this->pushErrorMessage($action, $errorMessage);
            cache()->put($action->id . '-progress', [
                'processed' => $cnt,
                'total' => count($items),
                'percent' => round($cnt * 100 / (count($items)))
            ], 600);
            $this->triggerMessage();
            $action->finished_at = Carbon::now();
            $action->save();
            return;
        }


        $hostelId = $hostel->id;

        try {

            foreach ($firstRow as $keyFirstRow => $itemFirstRow) {
                if (!empty($itemFirstRow)) {
                    $nameItem = trim($itemFirstRow);
                    $fee = HostelFee::query()
                        ->where('hostel_id', $hostelId)
                        ->where('name', $nameItem)
                        ->first();

                    if ($fee) {
                        if (empty($firstRow[$keyFirstRow + 1])) {
                            $start = $secondRow[$keyFirstRow];
                            if (str_contains($start, 'giá')) {
                                $indexArr[$keyFirstRow] = [
                                    'type' => 'value',
                                    'fee' => $fee->id
                                ];
                                $indexArr[$keyFirstRow + 1] = [
                                    'type' => 'qty',
                                    'fee' => $fee->id
                                ];

                            } else if (str_contains($start, 'đầu')) {
                                $indexArr[$keyFirstRow] = [
                                    'type' => 'start',
                                    'fee' => $fee->id
                                ];
                                $indexArr[$keyFirstRow + 1] = [
                                    'type' => 'end',
                                    'fee' => $fee->id
                                ];
                            } else {
                                $indexArr[$keyFirstRow] = [
                                    'type' => 'qty',
                                    'fee' => $fee->id
                                ];
                            }
                        } else {

                            $indexArr[$keyFirstRow] = [
                                'type' => 'qty',
                                'fee' => $fee->id
                            ];
                        }
                    }
                }

                //if()
            }


            $moneyDetailArr = [];
            foreach ($items as $itemR) {

                $month = '01/' . $itemR[4];
                $sum = 0;
                $monthItem = $month;

                $roomName = trim($itemR[2]);

                $contract = Contract::query()
                    ->where('name', trim($itemR[3]))
                    ->whereHas('room', function ($q) use ($roomName) {
                        $q->where('name', $roomName);
                    })
                    ->whereHas('hostel', function ($q) use ($ownerId) {
                        $q->where('owner_id', $ownerId);
                    })

                    ->where('status', '<>', Contract::LIQUIDATED)
                    ->first();
                if (!$contract) {

                    $cnt++;

                    $errorMessage = 'Không tìm thấy hợp đồng, tên: ' . $itemR[3];
                    $this->pushErrorMessage($action, $errorMessage);
                    cache()->put($action->id . '-progress', [
                        'processed' => $cnt,
                        'total' => count($items),
                        'percent' => round($cnt * 100 / (count($items)))
                    ], 600);
                    $this->triggerMessage();
                    continue;
                }
                $room = $contract->room;


                $counter = -1;


                foreach ($itemR as $key => $item) {
                    $counter++;
                    if (isset($indexArr[$key])) {

                        $newKey = $key;
                        $date = Carbon::createFromFormat('d/m/Y', $month);
                        $startTime = $date->copy()->startOfMonth();
                        $endTime = $date->copy()->endOfMonth();

                        $itemIndex = $indexArr[$newKey];
                        $feeId = $itemIndex['fee'];


                        $feeItem = HostelFee::find($feeId);
                        $qty = 0;
                        $value = 0;
                        $start = 0;
                        $end = 0;

                        if ($itemIndex['type'] == 'start') {
                            $start = intval($itemR[$newKey]);
                            $end = intval($itemR[$newKey + 1]);

                        }
                        if ($itemIndex['type'] == 'end') {
                            $start = intval($itemR[$newKey - 1]);
                            $end = intval($itemR[$newKey]);

                        } else if ($itemIndex['type'] == 'value') {
                            $value = intval($itemR[$newKey]);
                            $qty = intval($itemR[$newKey + 1]);
                        } else if ($itemIndex['type'] == 'qty') {
                            $qty = intval($itemR[$newKey]);
                        }


                        $isElectric = 0;
                        $isWater = 0;
                        $feeValue = 1;
                        $feeId = 0;
                        $amount = 0;


                        if ($feeItem) {


                            $feeValue = $feeItem->fee;
                            $qtyItem = $qty;

                            if ($feeItem->type == HostelFee::ELECTRIC || $feeItem->type == HostelFee::ELECTRIC_BY_CLOCK) {


                                $ew = [];
                                $isElectric = 1;
                                if ($start > $end) {
                                    continue;
                                }

                                $qtyItem = json_encode([
                                    'start' => $start,
                                    'end' => $end
                                ]);


                                $ew['end_electric'] = $end;
                                $ew['start_electric'] = $start;
                                $ew['delta_electric'] = $end - $start;
                                $ew['date_action'] = Carbon::createFromFormat('d/m/Y', $month)->toDateString();
                                $ew['room_id'] = $room->id;
                                $ew['hostel_id'] = $room->hostel->id;
                                $ew['contract_id'] = $contract->id;
                                $feeValue = 1;

                                if ($feeItem->type == HostelFee::ELECTRIC) {
                                    $amount = Functions::calculateElectricAmount($end - $start, $room, HostelFee::ELECTRIC, $feeItem->id);
                                } else {
                                    $feeValue = $feeItem->fee;
                                    $amount = ($end - $start) * $feeItem->fee;
                                }


                                $itemEw = ElectricWater::query()->whereBetween('date_action', [
                                    $startTime,
                                    $endTime
                                ])
                                    ->where('contract_id', $contract->id)
                                    ->where('room_id', $room->id)->first();

                                if(!empty($ew['start_electric']) && !empty($ew['end_electric'])) {
                                    if ($itemEw) {
                                        $itemEw->update($ew);
                                    } else {
                                        ElectricWater::create($ew);
                                    }
                                }

                            } else if ($feeItem->type == HostelFee::WATER || $feeItem->type == HostelFee::WATER_BY_CLOCK) {

                                $isWater = 1;
                                $ew = [];

                                if ($start > $end) {
                                    continue;
                                }
                                $qtyItem = json_encode([
                                    'start' => $start,
                                    'end' => $end
                                ]);

                                $ew['end_water'] = $end;
                                $ew['start_water'] = $start;
                                $ew['delta_water'] = $ew['end_water'] - $ew['start_water'];
                                $ew['date_action'] = Carbon::createFromFormat('d/m/Y', $month)->toDateString();
                                $ew['room_id'] = $room->id;
                                $ew['hostel_id'] = $room->hostel->id;
                                $ew['contract_id'] = $contract->id;


                                $feeValue = 1;
                                if ($feeItem->type == HostelFee::WATER) {
                                    $amount = Functions::calculateElectricAmount($end - $start, $room, HostelFee::WATER, $feeItem->id);
                                } else {
                                    $feeValue = $feeItem->fee;
                                    $amount = ($end - $start) * $feeItem->fee;
                                }


                                $itemEw = ElectricWater::query()->whereBetween('date_action', [
                                    $startTime,
                                    $endTime
                                ])
                                    ->where('contract_id', $contract->id)
                                    ->where('room_id', $room->id)->first();

                                if(!empty($ew['start_water']) && !empty($ew['end_water'])) {
                                    if ($itemEw) {
                                        $itemEw->update($ew);
                                    } else {
                                        ElectricWater::create($ew);
                                    }
                                }

                            } else if ($feeItem->type == HostelFee::DYNAMIC || $feeItem->type == HostelFee::WATER_DYNAMIC || $feeItem->type == HostelFee::ELECTRIC_DYNAMIC) {

                                $feeValue = Functions::filterInputNumber($value);
                                $amount = $feeValue * $qtyItem;
                            } else {
                                $amount = $feeValue * $qtyItem;
                            }


                            $sum += $amount;
                            $name = $feeItem->name;
                            $feeId = $feeItem->id;

                        } else {

                            $name = 'Khác';
                        }

                        if ($amount != 0) {

                            $values = [
                                'hostel_id' => $contract->room->hostel->id,
                                'room_id' => $contract->room->id,
                                'name' => $name,
                                'is_electric' => $isElectric,
                                'is_water' => $isWater,
                                'value' => $feeValue,
                                'qty' => $qtyItem,
                                'amount' => $amount,
                                'hostel_fee_id' => $feeId,
                            ];
                            if($contract->hostel->type_rent == Hostel::TYPE_RENT_EVERY) {
                                $checkMoneyDetail = MoneyDetail::query()
                                    ->where($values)
                                    ->where('created_at', '>=', Carbon::now()->subMinutes(5))
                                    ->whereHas('moneyInfo.contract', function ($q) use ($contract) {
                                        $q->where('contracts.id', $contract->id);
                                    })
                                    ->first();
                            } else {
                                $checkMoneyDetail = MoneyDetail::query()
                                    ->where('created_at', '>=', Carbon::now()->subMinutes(5))
                                    ->where($values)
                                    ->first();
                            }

                            if($checkMoneyDetail)
                            {
                                $checkMoneyDetail->update($values);
                                $moneyDetailArr[] = $checkMoneyDetail->id;
                            } else {
                                $moneyDetail = MoneyDetail::query()->create($values);
                                $moneyDetailArr[] = $moneyDetail->id;
                            }
                        }
                    }

                    if (!isset($itemR[$counter + 1])) {

                        if ($contract) {
                            $dateAction = Carbon::createFromFormat('d/m/Y', $monthItem)->toDateString();
                            try {
                                $startTime = Carbon::createFromFormat('d/m/Y', $monthItem)->startOfMonth()->startOfDay()->toDateString();
                                $endTime = Carbon::createFromFormat('d/m/Y', $monthItem)->endOfMonth()->endOfDay()->toDateString();
                                $monthCarbon = Carbon::createFromFormat('d/m/Y', $monthItem);
                            } catch (\Exception $exception) {
                                $moneyDetailArr = [];
                                continue;
                            }


                            $item = MoneyInfo::query()->where('room_id', $contract->room->id)
                                ->where('type', MoneyInfo::VOUCHER_SERVICE)
                                ->validate($contract->id)
                                ->whereBetween(
                                    'date_action', [$startTime, $endTime]
                                )->first();

                            $pay = 0;
                            $itemId = null;

                            if ($item) {

                                $cntCollectSpend = CollectSpend::query()
                                    ->where('money_info_id', $item->id)
                                    ->first();

                                if ($cntCollectSpend) {
                                    $moneyDetailArr = [];

                                    continue;
                                }
                                $itemId = $item->id;
                                $dateAction = $item->date_action->toDateString();
//                if ($monthCarbon->lessThan(Carbon::now())) {
//                    return response([
//                        'status' => 0,
//                        'message' => 'Hóa đơn cho tháng ' . $monthCarbon->month . ' đã tồn tại'
//                    ]);
//
//                }


                                if ($item->pay > 0) {
                                    $pay = $item->pay;
                                }
                                MoneyDetail::query()->where('money_info_id', $item->id)
                                    ->whereNotIn('id', $moneyDetailArr)
                                    ->delete();
                                $item->delete();
//							ElectricWater::query()->whereBetween( 'date_action', [
//								$startTime,
//								$endTime
//							] )
//							                      ->where( 'room_id', $room->id )
//							                      ->delete();

                            }


                            if (!empty($moneyDetailArr)) {
                                $moneyInfo = MoneyInfo::create([
                                    'hostel_id' => $contract->room->hostel->id,
                                    'user_id' => $this->userId,
                                    'room_id' => $contract->room->id,
                                    'amount' => $sum,
                                    'discount' => 0,
                                    'pay' => $pay,
                                    'remain' => $sum - 0 - $pay,
                                    'date_action' => $dateAction,
                                    'type' => MoneyInfo::VOUCHER_SERVICE,
                                    'contract_id' => $contract->id,
                                    'note' => ''
                                ]);
                            }

                            if (!empty($moneyDetailArr)) {
                                MoneyDetail::query()
                                    ->whereIn('id', array_unique($moneyDetailArr))
                                    ->update([
                                        'money_info_id' => $moneyInfo->id
                                    ]);


                                $sum = MoneyDetail::query()
                                    ->whereIn('id', $moneyDetailArr)
                                    ->sum('amount');

                                $moneyInfo->amount = $sum;
                                $moneyInfo->remain = $sum - 0 - $moneyInfo->pay;
                                $moneyInfo->save();
                            }


                            if (!empty($itemId)) {
                                Transaction::query()->where('money_info_id', $itemId)->update([
                                    'money_info_id' => $moneyInfo->id
                                ]);

                                CollectSpend::query()->where('money_info_id', $itemId)->update([
                                    'money_info_id' => $moneyInfo->id,
                                    'money_info_name' => $moneyInfo->name
                                ]);
                            }

                            $cnt++;
                            cache()->put($action->id . '-success-message', 'Đã import thành công: ' . $cnt . '/' . count($items) . ' hóa đơn', 600);
                            cache()->put($action->id . '-progress', [
                                'processed' => $cnt,
                                'total' => count($items),
                                'percent' => round($cnt * 100 / count($items))
                            ], 600);
                            $res = $pusher->trigger($channelName, 'success', 'Đã import thành công: ' . $cnt . '/' . count($items) . ' hóa đơn');
                            $this->triggerMessage();


                        }

                        $moneyDetailArr = [];

                    }
                }


            }
        } catch (\Exception $exception)
        {
            $action->finished_at = Carbon::now();
            $action->save();

            $cnt = $number;

            $errorMessage = 'Có lỗi xảy ra: '.$exception->getMessage();
            $this->pushErrorMessage($action, $errorMessage);
            cache()->put($action->id . '-progress', [
                'processed' => $cnt,
                'total' => count($items),
                'percent' => round($cnt * 100 / (count($items)))
            ], 600);
            $this->triggerMessage();
            $action->finished_at = Carbon::now();
            $action->save();
            return;
        }


        $action->finished_at = Carbon::now();
        $action->save();

    }
}