<?php

namespace Modules\Vrc\Http\Controllers\Registers;

use Illuminate\Http\Request;
use Modules\Vrc\Http\Controllers\VrcBaseController;
use Yajra\DataTables\Facades\DataTables;

/**
 * Generic, schema-driven CRUD engine for the VRC "register" screens (ISO 9001 /
 * 14001 / 45001 logs, work centers, storage bins, certifications, …). A subclass
 * only declares schema() — columns + form fields + permissions — and the engine
 * provides the AJAX DataTable, modal create/edit/delete using the shared
 * vrc-modal/vrc-form/vrc-delete conventions (partials/crud_scripts.blade.php).
 *
 * All rows are business-scoped; values are validated from the field types; select
 * columns render their option label (and a coloured badge when `badge` is set).
 */
abstract class AbstractRegisterController extends VrcBaseController
{
    /**
     * @return array{key:string,route:string,model:class-string,permView:string,permManage:string,
     *               title:string,singular:string,modalSize?:string,columns:array,fields:array,
     *               defaults?:array,beforeSave?:callable}
     */
    abstract protected function schema(): array;

    public function index()
    {
        $s = $this->schema();
        $this->guard($s['permView']);

        if (request()->ajax()) {
            $query = $s['model']::where('business_id', $this->businessId());

            $dt = DataTables::of($query);
            $raw = ['action'];

            foreach ($s['columns'] as $col) {
                $key = $col['key'];
                $dt->editColumn($key, function ($row) use ($col) {
                    return $this->renderCell($row, $col);
                });
                if (! empty($col['badge']) || ! empty($col['raw'])) {
                    $raw[] = $key;
                }
            }

            $dt->addColumn('action', function ($row) use ($s) {
                if (! auth()->user()->can($s['permManage'])) {
                    return '';
                }
                return '<button data-href="' . route($s['route'] . '.edit', $row->id) . '" class="btn btn-xs btn-primary vrc-modal-btn"><i class="fa fa-edit"></i></button> '
                    . '<button data-href="' . route($s['route'] . '.destroy', $row->id) . '" class="btn btn-xs btn-danger vrc-delete"><i class="fa fa-trash"></i></button>';
            });

            return $dt->rawColumns($raw)->make(true);
        }

        return view('vrc::registers.index', ['s' => $s]);
    }

    public function create()
    {
        $s = $this->schema();
        $this->guard($s['permManage']);
        return view('vrc::registers.form', ['s' => $s, 'row' => null]);
    }

    public function store(Request $request)
    {
        $s = $this->schema();
        $this->guard($s['permManage']);
        $data = $this->validated($request, $s);
        try {
            $data['business_id'] = $this->businessId();
            $data = array_merge($s['defaults'] ?? [], $data);
            if (! empty($s['beforeSave'])) {
                $data = ($s['beforeSave'])($data, $request, null);
            }
            $s['model']::create($data);
            return $this->ok(__('vrc::lang.added_success'));
        } catch (\Throwable $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    public function edit($id)
    {
        $s = $this->schema();
        $this->guard($s['permManage']);
        $row = $s['model']::where('business_id', $this->businessId())->findOrFail($id);
        return view('vrc::registers.form', ['s' => $s, 'row' => $row]);
    }

    public function update(Request $request, $id)
    {
        $s = $this->schema();
        $this->guard($s['permManage']);
        $data = $this->validated($request, $s);
        try {
            $row = $s['model']::where('business_id', $this->businessId())->findOrFail($id);
            if (! empty($s['beforeSave'])) {
                $data = ($s['beforeSave'])($data, $request, $row);
            }
            $row->update($data);
            return $this->ok(__('vrc::lang.updated_success'));
        } catch (\Throwable $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    public function destroy($id)
    {
        $s = $this->schema();
        $this->guard($s['permManage']);
        try {
            $s['model']::where('business_id', $this->businessId())->findOrFail($id)->delete();
            return $this->ok(__('vrc::lang.deleted_success'));
        } catch (\Throwable $e) {
            \Log::emergency($e->getMessage());
            return $this->fail();
        }
    }

    /** Build validation rules from the field definitions. */
    protected function validated(Request $request, array $s): array
    {
        $rules = [];
        foreach ($s['fields'] as $f) {
            $r = [];
            $r[] = ! empty($f['required']) ? 'required' : 'nullable';
            $r[] = match ($f['type'] ?? 'text') {
                'number'   => 'numeric',
                'date'     => 'date',
                'datetime' => 'date',
                'checkbox' => 'boolean',
                'select'   => 'string',
                default    => 'string',
            };
            if (! empty($f['max'])) {
                $r[] = 'max:' . $f['max'];
            }
            $rules[$f['name']] = implode('|', $r);
        }
        $data = $this->validate($request, $rules);

        // Normalise checkboxes (absent = false) and empty strings → null.
        foreach ($s['fields'] as $f) {
            $name = $f['name'];
            if (($f['type'] ?? '') === 'checkbox') {
                $data[$name] = $request->boolean($name);
            } elseif (array_key_exists($name, $data) && $data[$name] === '') {
                $data[$name] = null;
            }
        }
        return $data;
    }

    protected function renderCell($row, array $col)
    {
        $key = $col['key'];
        $val = $row->{$key};

        if (! empty($col['map'])) {
            $val = $col['map'][$val] ?? $val;
        }
        if (($col['type'] ?? '') === 'date' && $val) {
            $val = \Carbon\Carbon::parse($val)->format('d M Y');
        }
        if (! empty($col['badge'])) {
            $cls = $col['badge'][$row->{$key}] ?? 'default';
            $label = $col['map'][$row->{$key}] ?? $row->{$key};
            return '<span class="label label-' . $cls . '">' . e($label) . '</span>';
        }
        return $val === null || $val === '' ? '—' : e($val);
    }
}
