<?php
namespace App\Http\Controllers;

use App\Models as M;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;

class DocumentLibraryController extends Controller {
    /** Curated attachable owners: class => [label, crud-key for deep-link]. */
    public const OWNERS = [
        M\Customer::class => ['Customer', 'customers'],
        M\Supplier::class => ['Supplier', 'suppliers'],
        M\Project::class => ['Project', 'projects'],
        M\Quarry::class => ['Quarry', 'quarries'],
        M\Equipment::class => ['Equipment', 'equipment'],
        M\Employee::class => ['Employee', 'employees'],
        M\SalesInvoice::class => ['Sales invoice', 'sales-invoices'],
        M\PurchaseOrder::class => ['Purchase order', 'purchase-orders'],
        M\ClientIpc::class => ['Client IPC', 'client-ipcs'],
        M\MaintenanceWorkOrder::class => ['Work order', 'maintenance-work-orders'],
    ];
    public const UNFILED = 'unfiled';
    public const MAX_KB = 20480; // 20 MB
    public const MIMES = 'pdf,doc,docx,xls,xlsx,csv,txt,jpg,jpeg,png,gif,webp,zip';

    public function index(Request $r) {
        $this->need('docs.view');
        $q = M\Attachment::with('uploader')->orderByDesc('id');
        if ($r->filled('q')) $q->where('file_name', 'like', '%'.$r->q.'%');
        if ($r->filled('owner')) $q->where('attachable_type', $r->owner);
        if ($r->filled('kind')) {
            $k = $r->kind;
            if ($k === 'pdf') $q->where('mime', 'like', '%pdf%');
            elseif ($k === 'image') $q->where('mime', 'like', 'image/%');
            elseif ($k === 'sheet') $q->where(fn($w) => $w->where('mime', 'like', '%sheet%')->orWhere('mime', 'like', '%excel%')->orWhere('mime', 'like', '%csv%'));
            elseif ($k === 'doc') $q->where(fn($w) => $w->where('mime', 'like', '%word%')->orWhere('mime', 'like', '%text%'));
            elseif ($k === 'other') $q->where(fn($w) => $w->whereNull('mime')->orWhere('mime', 'not like', '%pdf%')->where('mime', 'not like', 'image/%'));
        }
        // Version groups: same owner + same filename = one document, many versions.
        $groups = $q->get()->groupBy(fn($a) => $a->attachable_type.'|'.$a->attachable_id.'|'.$a->file_name)
            ->map(function ($rows) {
                $ordered = $rows->sortBy('id')->values();
                return ['latest' => $ordered->last(), 'versions' => $ordered->reverse()->values(), 'count' => $ordered->count()];
            })->sortByDesc(fn($g) => $g['latest']->id)->values();
        $page = max(1, (int) $r->get('page', 1));
        $per = 25;
        $pager = new LengthAwarePaginator($groups->forPage($page, $per), $groups->count(), $per, $page, ['path' => $r->url(), 'query' => $r->query()]);
        return view('docs-library.index', ['groups' => $pager, 'owners' => self::OWNERS, 'req' => $r,
            'totalFiles' => M\Attachment::count(), 'totalBytes' => (int) M\Attachment::sum('size')]);
    }

    public function create() {
        $this->need('docs.create');
        return view('docs-library.create', ['owners' => self::OWNERS]);
    }

    public function store(Request $r) {
        $this->need('docs.create');
        $owner = $r->get('attachable_type', self::UNFILED);
        $rules = [
            'file' => 'required|file|max:'.self::MAX_KB.'|mimes:'.self::MIMES.'|extensions:'.self::MIMES,
            'attachable_type' => ['required', Rule::in(array_merge([self::UNFILED], array_keys(self::OWNERS)))],
            'file_name' => 'nullable|string|max:255',
        ];
        if ($owner !== self::UNFILED && isset(self::OWNERS[$owner])) {
            $rules['attachable_id'] = ['required', 'integer', Rule::exists((new $owner)->getTable(), 'id')];
        }
        $v = $r->validate($rules);
        $f = $r->file('file');
        $name = trim((string) ($v['file_name'] ?? '')) !== '' ? trim($v['file_name']) : $f->getClientOriginalName();
        $safe = preg_replace('/[^A-Za-z0-9._-]+/', '_', $name);
        $path = $f->storeAs('docs-library/'.date('Y/m'), uniqid().'_'.$safe, 'local');
        $a = M\Attachment::create([
            'attachable_type' => $owner,
            'attachable_id' => $owner === self::UNFILED ? 0 : (int) $v['attachable_id'],
            'file_name' => $name,
            'file_path' => $path,
            'mime' => $f->getMimeType(),
            'size' => $f->getSize(),
            'uploaded_by' => Auth::id(),
        ]);
        $ver = M\Attachment::where('attachable_type', $a->attachable_type)->where('attachable_id', $a->attachable_id)
            ->where('file_name', $a->file_name)->count();
        return redirect()->route('docs-library.index')->with('success', "Filed “{$name}” (v{$ver}).");
    }

    public function download(int $id) {
        $this->need('docs.view');
        $a = M\Attachment::findOrFail($id);
        if (!Storage::disk('local')->exists($a->file_path)) abort(404, 'File missing from storage.');
        return Storage::disk('local')->download($a->file_path, $a->file_name);
    }

    public function destroy(int $id) {
        $this->need('docs.delete');
        $a = M\Attachment::findOrFail($id);
        $shared = M\Attachment::where('file_path', $a->file_path)->where('id', '!=', $a->id)->exists();
        if (!$shared) Storage::disk('local')->delete($a->file_path);
        $a->delete();
        return redirect()->route('docs-library.index')->with('success', "Deleted “{$a->file_name}”.");
    }

    /** Human label + deep-link for an attachment owner. */
    public static function ownerInfo(M\Attachment $a): array {
        if ($a->attachable_type === self::UNFILED || !isset(self::OWNERS[$a->attachable_type])) {
            return ['Unfiled', null];
        }
        [$label, $key] = self::OWNERS[$a->attachable_type];
        $rec = null;
        try { $rec = $a->attachable; } catch (\Throwable $e) { $rec = null; }
        $tag = '#'.$a->attachable_id;
        if ($rec) foreach (['display_name', 'name', 'code', 'invoice_no', 'order_no', 'ticket_no', 'employee_no', 'ipc_no', 'wo_no'] as $f) {
            if (!empty($rec->{$f})) { $tag = $rec->{$f}; break; }
        }
        $url = null;
        try { $url = crud_url($key, 'show', $a->attachable_id); } catch (\Throwable $e) { $url = null; }
        return [$label.' · '.$tag, $url === '#' ? null : $url];
    }

    public static function kindOf(?string $mime): string {
        $m = (string) $mime;
        if (str_contains($m, 'pdf')) return 'PDF';
        if (str_starts_with($m, 'image/')) return 'Image';
        if (str_contains($m, 'sheet') || str_contains($m, 'excel') || str_contains($m, 'csv')) return 'Sheet';
        if (str_contains($m, 'word') || str_contains($m, 'text')) return 'Doc';
        if (str_contains($m, 'zip')) return 'Archive';
        return 'File';
    }
}
