<?php

namespace Modules\Internal\Http\Controllers\Api;

use App\Exceptions\ImportRowException;
use App\Helpers\Helper;
use App\Imports\PlansImport;
use App\Models\Benefit;
use App\Models\Claim;
use App\Models\Corporate;
use App\Models\CorporateBenefit;
use App\Models\Plan;
use App\Models\Service;
use App\Models\User;
use App\Services\ImportService;
use DB;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Maatwebsite\Excel\Facades\Excel;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use App\Models\File;
use Illuminate\Support\Facades\File as FacadesFile;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\CorporateService;

class CorporateController extends Controller
{
    /**
     * Display a listing of the resource.
     * @return Renderable
     */
    public function index(Request $request)
    {
        $corporates = Corporate::query()
            ->when($request->search, function ($query, $search) {
                return $query->where('name', 'LIKE', '%' . $search . '%')
                    ->orWhere('code', 'LIKE', '%' . $search . '%');
            })
            ->with('currentPolicy', 'subCorporates')
            ->withCount([
                'employees',
                'corporateBenefits',
                'corporatePlans',

                // 'claims'
            ])
            ->where('type', 'corporate')
            ->paginate(10);

        return $corporates;
    }

    /**
     * Show the form for creating a new resource.
     * @return Renderable
     */
    public function create()
    {
        $corporateGroups = Corporate::whereNull('parent_id')->get()->map(function ($corporate) {
            return [
                'value' => $corporate->id,
                'label' => $corporate->name . ' (' . $corporate->code . ')',
            ];
        });

        return response()->json([
            'corporate_groups' => $corporateGroups
        ]);
    }

    /**
     * Store a newly created resource in storage.
     * @param Request $request
     * @return Renderable
     */
    public function store(Request $request)
    {
       
        $request->validate([
            'code' => 'required|regex:/^[a-zA-Z0-9]+$/',
            'name' => 'required',
            // 'logo' => 'required',
            'policy_code' => 'required_with:policy_id',
            'policy_total_premi' => 'required_with:policy_code',
            'policy_minimal_deposit_percentage' => 'required_with:policy_code',
            'policy_minimal_deposit_net' => 'required_with:policy_code',
            'policy_minimal_alert_percentage' => 'required_with:policy_code',
            'policy_minimal_alert_net' => 'required_with:policy_code',
            'policy_stop_service_percentage' => 'required_with:policy_code',
            'policy_stop_service_net' => 'required_with:policy_code',
        ]);
        try {
            DB::beginTransaction();
            $corporate_data = $request->all();
            $corporate_data['type'] = !empty($corporate_data['type']) ? $corporate_data['type'] : 'corporate';

            $newCorporate = Corporate::create($request->all());
            if ($request->has('policy_code') && !empty($request->policy_code)) {
                $newCorporate->policies()->create([
                    'code' => $request->policy_code ?? NULL,
                    'total_premi' => $request->policy_total_premi ?? NULL,
                    'minimal_deposit_percentage' => $request->policy_minimal_deposit_percentage ?? NULL,
                    'minimal_deposit_net' => $request->policy_minimal_deposit_net ?? NULL,
                    'minimal_alert_percentage' => $request->policy_minimal_alert_percentage ?? NULL,
                    'minimal_alert_net' => $request->policy_minimal_alert_net ?? NULL,
                    'minimal_stop_service_percentage' => $request->policy_stop_service_percentage ?? NULL,
                    'minimal_stop_service_net' => $request->policy_stop_service_net ?? NULL,
                    'start' => $request->policy_start ?? NULL,
                    'end' => $request->policy_end ?? NULL,
                    'active' => $request->policy_active ?? true,
                ]);
            }

            // Service
            $services = [
                [
                    'id' => 1,
                    'name' => 'Out Patient',
                    'code' => 'OP',
                    'description' => 'Out Patient',
                ],
                [
                    'id' => 2,
                    'name' => 'Inpatient',
                    'code' => 'IP',
                    'description' => 'Inpatient',
                ],
                [
                    'id' => 3,
                    'name' => 'Dental',
                    'code' => 'DE',
                    'description' => 'Dental',
                ],
                [
                    'id' => 4,
                    'name' => 'Maternal',
                    'code' => 'MA',
                    'description' => 'Maternal',
                ],
                [
                    'id' => 5,
                    'name' => 'Optical',
                    'code' => 'OPT',
                    'description' => 'Optical',
                ],
                [
                    'id' => 6,
                    'name' => 'Medical Check Up',
                    'code' => 'MCU',
                    'description' => 'Medical Check Up',
                ],
            ];

            foreach ($services as $service) {

                $corporateService = $newCorporate->corporateServices()->create([
                    'service_code' => $service['code'],
                    'status' => 'inactive'
                ]);

                $corporateService->configs()->insert([
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'gp_external_doctor_online',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'gp_external_doctor_offline',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'gp_internal_doctor_online',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'gp_internal_doctor_offline',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'sp_external_doctor_online',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'sp_external_doctor_offline',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'sp_internal_doctor_online',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'sp_internal_doctor_offline',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'vitamins',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'delivery_fee',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'general_practitioner_fee',
                        'value' => false,
                    ],
                    [
                        'corporate_service_id' => $corporateService->id,
                        'name' => 'specialist_practitioner_fee',
                        'value' => false,
                    ],
                ]);
            }

            // TODO Remove This
            // Assign Managed to Manager one
            $managerOne = User::where('email', 'manager+one@gmail.com')->first();
            $managerOne->managedCorporates()->attach($newCorporate);

            if ($request->hasFile('logo')) {
                $pathFileAvatar = File::storeFile('avatar', $newCorporate->id, $request->file('logo'));
                $newCorporate->files()->updateOrCreate([
                    'type' => 'avatar',
                    'name' => File::getFileName('avatar', $newCorporate->id, $request->file('logo')),
                    'extension' => $request->file('logo')->getClientOriginalExtension(),
                    'path' => $pathFileAvatar,
                    'created_by' => auth()->user()->id,
                    'updated_by' => auth()->user()->id,
                ]);
            }


            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }

        return $newCorporate;
    }

    /**
     * Show the specified resource.
     * @param int $id
     * @return Renderable
     */
    public function show($id)
    {
        $corporate = Corporate::query()
            ->with(['currentPolicy', 'plans'])
            ->withCount('corporatePlans')
            ->withCount('employees')
            // ->withCount('employees.claims')
            ->findOrFail($id);
        $plans = $corporate['plans']->map(function ($plan) {
            return [
                'id' => $plan['id'],
                'code' => $plan['code'],
                'corporate_id' => $plan['corporate_id'],
                'corporate_plan_id' => $plan['corporate_plan_id'],
            ];
        });

        unset($corporate['plans']);
        $corporate['plans'] = $plans;

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

    /**
     * Show the form for editing the specified resource.
     * @param int $id
     * @return Renderable
     */
    public function edit($id)
    {
        $corporate = Corporate::findOrFail($id)->load('currentPolicy');

        return $corporate;
    }

    /**
     * Update the specified resource in storage.
     * @param Request $request
     * @param int $id
     * @return Renderable
     */
    public function update(Request $request, $id)
    {
        $request->validate([
            'code' => 'required|regex:/^[a-zA-Z0-9]+$/',
            'name' => 'required',
            'policy_code' => 'required_with:policy_id',
            'policy_total_premi' => 'required_with:policy_code',
            'policy_minimal_deposit_percentage' => 'required_with:policy_code',
            'policy_minimal_deposit_net' => 'required_with:policy_code',
            'policy_minimal_alert_percentage' => 'required_with:policy_code',
            'policy_minimal_alert_net' => 'required_with:policy_code',
            'policy_stop_service_percentage' => 'required_with:policy_code',
            'policy_stop_service_net' => 'required_with:policy_code',
        ]);

        try {
            DB::beginTransaction();
            //karena pake formdata
            $linkingRules = $request->linking_rules;
            $linkingRules = explode(',', $linkingRules);

            $corporate = Corporate::findOrFail($id);
            $corporate->fill($request->all());
            $corporate->linking_rules = $linkingRules;
            $corporate->save();

            $corporate->policies()->updateOrCreate(
                ['id' => $request->policy_id],
                [
                    'code' => $request->policy_code ?? NULL,
                    'total_premi' => $request->policy_total_premi ?? NULL,
                    'minimal_deposit_percentage' => $request->policy_minimal_deposit_percentage ?? NULL,
                    'minimal_deposit_net' => $request->policy_minimal_deposit_net ?? NULL,
                    'minimal_alert_percentage' => $request->policy_minimal_alert_percentage ?? NULL,
                    'minimal_alert_net' => $request->policy_minimal_alert_net ?? NULL,
                    'minimal_stop_service_percentage' => $request->policy_stop_service_percentage ?? NULL,
                    'minimal_stop_service_net' => $request->policy_stop_service_net ?? NULL,
                    'start' => $request->policy_start ?? NULL,
                    'end' => $request->policy_end ?? NULL,
                    'active' => $request->policy_active ?? true,
                ]
            );

            if ($request->hasFile('logo')) {
                $pathFileAvatar = File::storeFile('avatar', $corporate->id, $request->file('logo'));

                $corporate->files()->updateOrCreate([
                    'type' => 'avatar',
                    'name' => File::getFileName('avatar', $corporate->id, $request->file('logo')),
                    'extension' => $request->file('logo')->getClientOriginalExtension(),
                    'path' => $pathFileAvatar,
                    'created_by' => auth()->user()->id,
                    'updated_by' => auth()->user()->id,
                ]);
            }

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }

        return $corporate;
    }

    /**
     * Remove the specified resource from storage.
     * @param int $id
     * @return Renderable
     */
    public function destroy($id)
    {
        //
    }

    public function activation(Request $request, $corporate_id)
    {
        $request->validate([
            'active' => 'required'
        ]);

        // abort(404);

        $corporate = Corporate::findOrFail($corporate_id);
        $corporate->active = $request->active == '1';

        if ($corporate->save()) {
            return response()->json([
                'corporate' => $corporate,
                'message' => 'Status Updated Successfully'
            ]);
        }
    }

    public function importPlanBenefit(Request $request, $corporate_id)
    {
        $request->validate([
            'file' => 'required|file|mimes:xls,xlsx,csv,txt',
        ]);
        $file_name = now()->getPreciseTimestamp(3) . '-' . $request->file('file')->getClientOriginalName();
        $file = $request->file('file')->storeAs('temp', $file_name);
        $corporate = Corporate::with(['plans'])->findOrFail($corporate_id);

        $import = new ImportService();
        $import->read(Storage::path('temp/' . $file_name));
        $import->write(Storage::disk('public')->path('temp/result-' . $file_name), 'xsls');

        foreach ($import->sheetsIterator() as $sheetIndex => $sheet) {
            if (!in_array($sheet->getName(), ['Plan', 'Benefit'])) {
                continue;
            } else {
                if ($sheetIndex == 1) { // Rename First Sheet to Writer
                    $firstWriterSheet = $import->writer->getCurrentSheet();
                    $firstWriterSheet->setName($sheet->getName());
                } else { // Add New Sheet to Writer
                    $nextWriterSheet = $import->writer->addNewSheetAndMakeItCurrent();
                    $nextWriterSheet->setName($sheet->getName());
                }

                if ($sheet->getName() == 'Plan') {
                    $headers_map_to_table_fields = Plan::$doc_headers_to_field_map;
                } else if ($sheet->getName() == 'Benefit') {
                    $headers_map_to_table_fields = CorporateBenefit::$doc_headers_to_field_map;
                }

                // Write Header to File
                $result_headers = array_keys($headers_map_to_table_fields);
                $result_headers = array_merge($result_headers, ['Ingest Code', 'Ingest Note']);
                $import->addArrayToRow($result_headers);
            }

            $doc_headers_indexes = [];
            foreach ($sheet->getRowIterator() as $index => $row) {
                if ($index == 1) { // First Row Must be Header
                    foreach ($row->getCells() as $index => $cell) {
                        $title = $cell->getValue();
                        $title = preg_replace("/\r|\n/", " ", $title);
                        $title = preg_replace('/\xc2\xa0/', " ", $title);
                        $title = rtrim($title);
                        $title = ltrim($title);
                        $doc_headers_indexes[$index] = $title;
                    }
                    // TODO Validate if First Row not Header
                } else { // Next Row Should be Data
                    $row_data = [];

                    foreach ($row->getCells() as $header_index => $cell) {
                        if (isset($headers_map_to_table_fields[$doc_headers_indexes[$header_index]]))
                            $row_data[$headers_map_to_table_fields[$doc_headers_indexes[$header_index]]] = $cell->getValue();
                    }

                    try { // Process the Row Data
                        $corporateService = new CorporateService();
                        if ($sheet->getName() == 'Plan') {
                            $corporateService->handlePlanRow($corporate, $row_data);
                        } else if ($sheet->getName() == 'Benefit') {
                            $corporateService->handleBenefitRow($corporate, $row_data);
                        }

                        // Write Success Result to File
                        $import->addArrayToRow(array_merge($row_data, [
                            'Ingest Code' => 200,
                            'Ingest Note' => 'Success',
                        ]), $sheet->getName());
                    } catch (ImportRowException $e) {
                        // Write Data Validation Error to File
                        $import->addArrayToRow(array_merge($row_data, [
                            'Ingest Code' => $e->getCode(),
                            'Ingest Note' => $e->getMessage(),
                        ]), $sheet->getName());
                    } catch (\Exception $e) {
                        // throw new \Exception($e);
                        // Write Server Error to File
                        $import->addArrayToRow(array_merge($row_data, [
                            'Ingest Code' => 500,
                            'Ingest Note' => env('APP_DEBUG') ? $e->getMessage() : 'Server Error',
                        ]), $sheet->getName());
                    }
                }
            }
        }
        $import->reader->close();
        Storage::delete('temp/' . $file_name);
        $import->writer->close();

        return [
            // 'total_successed_row' => $imported_plan_data,
            // 'total_failed_row' => count($failed_plan_data),
            // 'failed_row' => $failed_plan_data,
            'result_file' => [
                'url' => Storage::disk('public')->url('temp/result-' . $file_name),
                'name' => 'result-' . $file_name,
            ]
        ];
    }

    public function importDocumentExample($document_type) 
    {
        switch ($document_type) {
            case 'plan-benefit':
                return Helper::responseJson([
                    'file_name' => "Corporate Plan & Benefit Import.xlsx",
                    "file_url" => url('files/Corporate Plan & Benefit Import.xlsx')
                ]);
                break;
            case 'member':
                return Helper::responseJson([
                    'file_name' => "Corporate Membership Import.xlsx",
                    "file_url" => url('files/Corporate Membership Import.xlsx')
                ]);
                break;            
            case 'diagnosis-exclusion':
                return Helper::responseJson([
                    'file_name' => "Corporate Exclusion Import.xlsx",
                    "file_url" => url('files/Corporate Exclusion Import.xlsx')
                ]);
                break;            
            default:
                return Helper::responseJson([], 'error', 404);
                break;
        }
    }
    
}
