<?php

namespace Modules\MedOrganization\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Yajra\DataTables\Facades\DataTables;

/**
 * Department CRUD over ClinicCore's clc_departments incl. the org extension
 * columns (spec §5 department; REUSE-MAP §5 "extend"). The ClinicCore model
 * is reused via FQCN — never redeclared here.
 */
class DepartmentController extends MedOrgBaseController
{
    public function index()
    {
        $this->guard('medorg.department.manage');

        if (request()->ajax()) {
            $bid = $this->businessId();

            $rows = DB::table('clc_departments as d')
                ->leftJoin('clc_departments as parent', 'parent.id', '=', 'd.parent_department_id')
                ->leftJoin('business_locations as bl', 'bl.id', '=', 'd.business_location_id')
                ->leftJoin('users as head', 'head.id', '=', 'd.head_user_id')
                ->where('d.business_id', $bid)
                ->select([
                    'd.id', 'd.name', 'd.code', 'd.dept_type', 'd.status', 'd.sort_order',
                    'parent.name as parent_name', 'bl.name as location_name',
                    DB::raw("TRIM(CONCAT(COALESCE(head.surname, ''), ' ', COALESCE(head.first_name, ''), ' ', COALESCE(head.last_name, ''))) as head_name"),
                ]);

            return DataTables::of($rows)
                ->editColumn('dept_type', fn ($r) => $r->dept_type ? __('medorganization::lang.dept_type_' . $r->dept_type) : '—')
                ->editColumn('status', fn ($r) => $r->status === 'active'
                    ? '<span class="label label-success">' . __('medorganization::lang.status_active') . '</span>'
                    : '<span class="label label-default">' . __('medorganization::lang.status_inactive') . '</span>')
                ->addColumn('action', function ($r) {
                    return '<button data-href="' . route('medorg.departments.edit', $r->id) . '" class="btn btn-xs btn-primary medorg-modal-btn"><i class="fa fa-edit"></i></button> '
                        . '<button data-href="' . route('medorg.departments.destroy', $r->id) . '" class="btn btn-xs btn-danger medorg-delete"><i class="fa fa-trash"></i></button>';
                })
                ->rawColumns(['status', 'action'])
                ->make(true);
        }

        return view('medorganization::departments.index');
    }

    public function create()
    {
        $this->guard('medorg.department.manage');

        return view('medorganization::departments.create', $this->formData());
    }

    public function store(Request $request)
    {
        $this->guard('medorg.department.manage');
        $data = $this->rules($request);

        try {
            $payload = $this->payload($request, $data);
            if ($payload === null) {
                return $this->fail(__('medorganization::lang.invalid_working_hours_json'));
            }
            $payload['business_id'] = $this->businessId();
            $payload['status'] = $request->input('status', 'active') === 'active' ? 'active' : 'inactive';

            \Modules\ClinicCore\Entities\ClcDepartment::create($payload);

            return $this->ok(__('medorganization::lang.added_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    public function edit($id)
    {
        $this->guard('medorg.department.manage');

        $department = \Modules\ClinicCore\Entities\ClcDepartment::forBusiness($this->businessId())->findOrFail($id);

        return view('medorganization::departments.edit', array_merge($this->formData((int) $id), compact('department')));
    }

    public function update(Request $request, $id)
    {
        $this->guard('medorg.department.manage');
        $data = $this->rules($request);

        try {
            $department = \Modules\ClinicCore\Entities\ClcDepartment::forBusiness($this->businessId())->findOrFail($id);

            // A department cannot be its own parent.
            if (! empty($data['parent_department_id']) && (int) $data['parent_department_id'] === (int) $department->id) {
                return $this->fail(__('medorganization::lang.parent_cannot_be_self'));
            }

            $payload = $this->payload($request, $data);
            if ($payload === null) {
                return $this->fail(__('medorganization::lang.invalid_working_hours_json'));
            }
            $payload['status'] = $request->input('status', 'active') === 'active' ? 'active' : 'inactive';

            $department->update($payload);

            return $this->ok(__('medorganization::lang.updated_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    public function destroy($id)
    {
        $this->guard('medorg.department.manage');

        try {
            $bid = $this->businessId();
            $department = \Modules\ClinicCore\Entities\ClcDepartment::forBusiness($bid)->findOrFail($id);

            // Keep referential sanity without touching other modules' data.
            if (DB::table('org_rooms')->where('business_id', $bid)->where('department_id', $department->id)->exists()) {
                return $this->fail(__('medorganization::lang.department_has_rooms'));
            }

            DB::table('org_user_departments')->where('business_id', $bid)->where('department_id', $department->id)->delete();
            if (Schema::hasColumn('clc_departments', 'parent_department_id')) {
                DB::table('clc_departments')->where('business_id', $bid)
                    ->where('parent_department_id', $department->id)
                    ->update(['parent_department_id' => null]);
            }

            $department->delete();

            return $this->ok(__('medorganization::lang.deleted_success'));
        } catch (\Exception $e) {
            \Log::emergency($e->getMessage());

            return $this->fail();
        }
    }

    protected function rules(Request $request): array
    {
        return $this->validate($request, [
            'name'                 => 'required|string|max:100',
            'code'                 => 'nullable|string|max:20',
            'dept_type'            => 'nullable|in:clinical,diagnostic,administrative,support',
            'parent_department_id' => 'nullable|integer',
            'head_user_id'         => 'nullable|integer',
            'working_hours'        => 'nullable|string',
            'business_location_id' => 'nullable|integer',
            'sort_order'           => 'nullable|integer|min:0',
            'description'          => 'nullable|string',
        ]);
    }

    /** Build the write payload; null on invalid working-hours JSON. */
    protected function payload(Request $request, array $data): ?array
    {
        $workingHours = $this->jsonOrNull($request->input('working_hours'), $jsonError);
        if ($jsonError) {
            return null;
        }

        $bid = $this->businessId();

        $parentId = ! empty($data['parent_department_id']) ? (int) $data['parent_department_id'] : null;
        if ($parentId && ! DB::table('clc_departments')->where('business_id', $bid)->where('id', $parentId)->exists()) {
            $parentId = null;
        }

        $locationId = ! empty($data['business_location_id']) ? (int) $data['business_location_id'] : null;
        if ($locationId && ! DB::table('business_locations')->where('business_id', $bid)->where('id', $locationId)->exists()) {
            $locationId = null;
        }

        return [
            'name'                 => $data['name'],
            'code'                 => $data['code'] ?? null,
            'dept_type'            => $data['dept_type'] ?? null,
            'parent_department_id' => $parentId,
            'head_user_id'         => ! empty($data['head_user_id']) ? (int) $data['head_user_id'] : null,
            'working_hours'        => $workingHours !== null ? json_encode($workingHours) : null,
            'business_location_id' => $locationId,
            'sort_order'           => (int) ($data['sort_order'] ?? 0),
            'description'          => $data['description'] ?? null,
        ];
    }

    protected function formData(?int $excludeId = null): array
    {
        $parents = \Modules\ClinicCore\Entities\ClcDepartment::forBusiness($this->businessId())
            ->when($excludeId, fn ($q) => $q->where('id', '!=', $excludeId))
            ->orderBy('name')
            ->pluck('name', 'id')
            ->toArray();

        return [
            'parents'   => $parents,
            'users'     => \App\User::forDropdown($this->businessId(), false),
            'locations' => $this->locations(),
        ];
    }
}
