<?php
namespace App\Http\Controllers;
use App\Models as M;
use App\Services\SequenceService;
use App\Services\StockService;
use App\Support\CrudRegistry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class MaintenanceWorkOrderController extends Controller {
    public function index(Request $r) { return app(CrudController::class)->index($r, 'maintenance-work-orders'); }
    public function show(int $id) { return app(CrudController::class)->show('maintenance-work-orders', $id); }
    public function create() {
        $this->need('fleet.create');
        return view('docs.work-order.form', $this->formData(new M\MaintenanceWorkOrder(['reported_date' => date('Y-m-d'), 'priority' => 'medium', 'maintenance_type' => 'breakdown'])));
    }
    public function store(Request $r) {
        $this->need('fleet.create');
        $d = $this->validated($r);
        $w = M\MaintenanceWorkOrder::create($d + ['wo_no' => SequenceService::next('work_order'), 'status' => 'open']);
        $this->saveParts($w, $r->input('parts', []));
        return redirect()->route('maintenance-work-orders.show', $w)->with('success', 'Work order '.$w->wo_no.' opened.');
    }
    public function edit(int $id) {
        $this->need('fleet.edit');
        $w = M\MaintenanceWorkOrder::with('parts')->findOrFail($id);
        abort_unless(in_array($w->status, ['open', 'in-progress', 'on-hold']), 403, 'Closed orders cannot be edited.');
        return view('docs.work-order.form', $this->formData($w));
    }
    public function update(Request $r, int $id) {
        $this->need('fleet.edit');
        $w = M\MaintenanceWorkOrder::findOrFail($id);
        abort_unless(in_array($w->status, ['open', 'in-progress', 'on-hold']), 403, 'Closed orders cannot be edited.');
        $w->update($this->validated($r));
        $w->parts()->delete();
        $this->saveParts($w, $r->input('parts', []));
        return redirect()->route('maintenance-work-orders.show', $w)->with('success', 'Work order updated.');
    }
    public function destroy(int $id) {
        $this->need('fleet.delete');
        $w = M\MaintenanceWorkOrder::findOrFail($id);
        abort_unless($w->status === 'open', 403, 'Only open orders can be deleted.');
        $w->delete();
        return redirect()->route('maintenance-work-orders.index')->with('success', 'Work order deleted.');
    }
    public function start(int $id) {
        $this->need('fleet.edit');
        $w = M\MaintenanceWorkOrder::findOrFail($id);
        abort_unless($w->status === 'open', 403, 'Only open orders can start.');
        DB::transaction(function () use ($w) {
            $w->update(['status' => 'in-progress', 'started_at' => now()]);
            $w->equipment()->update(['status' => 'down-maintenance']);
        });
        return back()->with('success', 'Work started; equipment marked down.');
    }
    public function complete(Request $r, int $id) {
        $this->need('fleet.approve');
        $w = M\MaintenanceWorkOrder::with('parts')->findOrFail($id);
        abort_unless(in_array($w->status, ['open', 'in-progress', 'on-hold']), 403, 'Order cannot be completed.');
        $d = $r->validate(['work_done' => 'nullable|max:2000', 'labour_cost' => 'nullable|numeric|min:0', 'warehouse_id' => 'nullable|exists:warehouses,id']);
        DB::transaction(function () use ($w, $d) {
            $parts = (float) $w->parts()->sum('amount');
            $labour = (float) ($d['labour_cost'] ?? $w->labour_cost);
            $w->update(['status' => 'completed', 'completed_at' => now(), 'work_done' => $d['work_done'] ?? $w->work_done,
                'parts_cost' => $parts, 'labour_cost' => $labour, 'total_cost' => round($parts + $labour, 2),
                'downtime_hours' => $w->started_at ? round($w->started_at->diffInHours(now(), true), 2) : $w->downtime_hours]);
            if (!empty($d['warehouse_id'])) {
                foreach ($w->parts as $p) {
                    StockService::postLedger(date('Y-m-d'), $p->item_id, $d['warehouse_id'], 'issue', 0, $p->qty, $p->rate, 'work_order', $w->id, ['equipment_id' => $w->equipment_id], 'WO '.$w->wo_no);
                }
            }
            $w->equipment()->update(['status' => 'available']);
        });
        return back()->with('success', 'Work order completed; parts issued & equipment released.');
    }
    public function close(int $id) {
        $this->need('fleet.approve');
        $w = M\MaintenanceWorkOrder::findOrFail($id);
        abort_unless($w->status === 'completed', 403, 'Only completed orders can close.');
        $w->update(['status' => 'closed', 'approved_by' => Auth::id()]);
        return back()->with('success', 'Work order closed.');
    }
    public function print(Request $r, int $id) {
        $this->need('fleet.view');
        $doc = M\MaintenanceWorkOrder::with('equipment', 'parts.item')->findOrFail($id);
        if ($r->get('pdf')) return \App\Services\PdfService::download('docs.work-order.print', ['w' => $doc], 'WO-'.($doc->wo_no ?? $id).'.pdf');
        return view('docs.work-order.print', ['w' => $doc]);
    }
    protected function validated(Request $r): array {
        return $r->validate(['equipment_id' => 'required|exists:equipment,id', 'reported_date' => 'required|date', 'reported_by' => 'nullable|max:100',
            'maintenance_type' => 'required|in:preventive,breakdown,accident,tyre,electrical', 'priority' => 'required|in:low,medium,high,critical',
            'meter_at_breakdown' => 'nullable|numeric', 'problem_description' => 'nullable|max:2000', 'assigned_technician' => 'nullable|max:100',
            'work_done' => 'nullable|max:2000', 'labour_cost' => 'nullable|numeric|min:0']);
    }
    protected function saveParts(M\MaintenanceWorkOrder $w, array $parts): void {
        foreach ($parts as $p) {
            if (empty($p['item_id']) || empty($p['qty'])) continue;
            $item = M\StockItem::find($p['item_id']);
            $rate = (float) ($p['rate'] ?? 0) ?: (float) $item->avg_cost_rate;
            $w->parts()->create(['item_id' => $item->id, 'qty' => $p['qty'], 'rate' => $rate, 'amount' => round($p['qty'] * $rate, 2)]);
        }
        $w->update(['parts_cost' => (float) $w->parts()->sum('amount'), 'total_cost' => round((float) $w->parts()->sum('amount') + (float) $w->labour_cost, 2)]);
    }
    protected function formData(M\MaintenanceWorkOrder $w): array {
        return ['record' => $w, 'isNew' => !$w->exists, 'cfg' => CrudRegistry::get('maintenance-work-orders'), 'key' => 'maintenance-work-orders',
            'docNo' => $w->exists ? $w->wo_no : SequenceService::peek('work_order'),
            'equipment' => M\Equipment::where('is_active', true)->orderBy('code')->get(),
            'items' => M\StockItem::where('is_active', true)->orderBy('name')->get(),
            'warehouses' => M\Warehouse::orderBy('name')->get()];
    }
}
