<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Supplier;
use App\Models\PartyType;
use App\Models\Warehouse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\Rule;
use Symfony\Component\HttpFoundation\StreamedResponse;

class SuppliersController extends Controller
{
    public function index(Request $request)
    {
        $q = trim((string) $request->get('q', ''));

        $suppliers = Supplier::query()
            ->when($q !== '', function ($query) use ($q) {
                $query->where(function ($qb) use ($q) {
                    $qb->where('name', 'like', "%{$q}%")
                       ->orWhere('company_name', 'like', "%{$q}%")
                       ->orWhere('email', 'like', "%{$q}%")
                       ->orWhere('personal_phone', 'like', "%{$q}%")
                       ->orWhere('bussiness_phone', 'like', "%{$q}%");
                });
            })
            ->latest('id')
            ->paginate(10)
            ->withQueryString();

        return view('suppliers.index', compact('suppliers', 'q'));
    }

    public function create()
    {
        $partyTypes = $this->getPartyTypes();
        $bagWares   = $this->getBagWares();
        return view('suppliers.create', compact('partyTypes', 'bagWares'));
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            // supplierid ইচ্ছাকৃতভাবে mass-assign করবো না
            'name'              => ['nullable', 'string', 'max:191'],
            'supplier_type'     => ['nullable', 'integer'],
            'account_id'        => ['nullable', 'integer'],
            'company_name'      => ['nullable', 'string', 'max:191'],
            'personal_phone'    => ['required', 'string', 'max:191'],
            'bussiness_phone'   => ['nullable', 'string'],
            'email'             => ['nullable', 'email', 'max:191', Rule::unique('rm_suppliers', 'email')],
            'address'           => ['nullable', 'string', 'max:191'],
            'opening_balance'   => ['nullable', 'numeric'],
            'current_balance'   => ['nullable', 'numeric'],
            'due_limit'         => ['nullable', 'numeric'],
            'remarks'           => ['nullable', 'string', 'max:191'],
            'discount_type'     => ['nullable', 'integer'],
            'discount'          => ['nullable', 'numeric'],
            'assume_rate'       => ['nullable', 'numeric'],
            'image'             => ['nullable', 'string'],
            'status'            => ['nullable', 'integer'],
            'bag_warehouse_id'  => ['required', 'integer'],
            'bag_opening'       => ['required', 'integer'],
            'party_type_id'     => ['nullable', 'integer'],
        ]);

        // নতুন রেকর্ড: supplierid জোর করে সেট করবো (mass-assign নয়)
        $supplier = new Supplier($data);
        $supplier->supplierid      = $this->generateSupplierId();
        $supplier->created_by      = Auth::id() ?? 1;
        $supplier->current_balance = $supplier->current_balance ?? 0.00;
        $supplier->save();

        return redirect()->route('suppliers.index')->with('success', 'Supplier created successfully.');
    }

    public function show(Supplier $supplier)
    {
        abort(404);
    }

    public function edit(Supplier $supplier)
    {
        $partyTypes = $this->getPartyTypes();
        $bagWares   = $this->getBagWares();
        return view('suppliers.edit', compact('supplier', 'partyTypes', 'bagWares'));
    }

    public function update(Request $request, Supplier $supplier)
    {
        // supplierid ইচ্ছাকৃতভাবে নেই
        $data = $request->validate([
            'name'              => ['nullable', 'string', 'max:191'],
            'supplier_type'     => ['nullable', 'integer'],
            'account_id'        => ['nullable', 'integer'],
            'company_name'      => ['nullable', 'string', 'max:191'],
            'personal_phone'    => ['required', 'string', 'max:191'],
            'bussiness_phone'   => ['nullable', 'string'],
            'email'             => ['nullable', 'email', 'max:191', Rule::unique('rm_suppliers', 'email')->ignore($supplier->id)],
            'address'           => ['nullable', 'string', 'max:191'],
            'opening_balance'   => ['nullable', 'numeric'],
            'current_balance'   => ['nullable', 'numeric'],
            'due_limit'         => ['nullable', 'numeric'],
            'remarks'           => ['nullable', 'string', 'max:191'],
            'discount_type'     => ['nullable', 'integer'],
            'discount'          => ['nullable', 'numeric'],
            'assume_rate'       => ['nullable', 'numeric'],
            'image'             => ['nullable', 'string'],
            'status'            => ['nullable', 'integer'],
            'bag_warehouse_id'  => ['required', 'integer'],
            'bag_opening'       => ['required', 'integer'],
            'party_type_id'     => ['nullable', 'integer'],
        ]);

        // যেকোনো নামেই এলে ড্রপ করুন (সেফগার্ড)
        unset($data['supplierid'], $data['supplierId'], $data['supplier_id']);

        // নিশ্চিত করুন যে original supplierid-ই থাকবে
        $supplier->supplierid = $supplier->getOriginal('supplierid') ?? $supplier->supplierid;

        $supplier->fill($data);
        $supplier->updated_by = Auth::id();
        $supplier->save();

        return redirect()->route('suppliers.index')->with('success', 'Supplier updated successfully.');
    }

    public function destroy(Supplier $supplier)
    {
        $supplier->delete();
        return redirect()->route('suppliers.index')->with('success', 'Supplier deleted successfully.');
    }

    public function toggle(Supplier $supplier)
    {
        $table = (new Supplier)->getTable();
        $col   = Schema::hasColumn($table, 'is_active') ? 'is_active'
               : (Schema::hasColumn($table, 'status') ? 'status' : null);

        if ($col) {
            $supplier->{$col} = (int)!((int)($supplier->{$col} ?? 0));
        }

        $supplier->updated_by = Auth::id();
        $supplier->save();

        return back()->with('success', 'Supplier status updated.');
    }

    /* ---------- CSV HUB ---------- */
    public function csv(Request $request) { return $this->csvHub($request); }

    public function csvHub(Request $request)
    {
        $action = strtolower((string)$request->get('action', 'list'));

        if ($request->isMethod('get') && $action === 'upload') {
            return view('suppliers.csv-upload');
        }

        if ($request->isMethod('post') && $action === 'import') {
            $request->validate(['file' => ['required', 'file', 'mimes:csv,txt', 'max:4096']]);
            $path = $request->file('file')->store('imports');
            $full = Storage::path($path);
            $imported = $this->stageCsv($full);

            return redirect()->route('suppliers.csv', ['action'=>'list'])
                ->with('success', "CSV uploaded. Staged {$imported} rows.");
        }

        if ($request->isMethod('get') && $action === 'import50') {
            $count = $this->importBatch(50);
            return redirect()->route('suppliers.csv', ['action'=>'list'])
                ->with('success', "Imported {$count} rows into suppliers.");
        }

        if ($request->isMethod('get') && $action === 'import_one') {
            $id = (int) $request->get('id');
            $ok = $this->importOne($id);
            return redirect()->route('suppliers.csv', ['action'=>'list'])
                ->with($ok ? 'success' : 'error', $ok ? 'Row imported.' : 'Row not found or invalid.');
        }

        if ($request->isMethod('get') && $action === 'delete') {
            $id = (int) $request->get('id');
            DB::table('supplier_staging')->where('id', $id)->delete();
            return redirect()->route('suppliers.csv', ['action'=>'list'])
                ->with('success', 'Row deleted.');
        }

        if ($request->isMethod('get') && $action === 'edit') {
            $id = (int) $request->get('id');
            $row = DB::table('supplier_staging')->where('id', $id)->first();
            abort_unless($row, 404);
            return view('suppliers.csv-edit', compact('row'));
        }

        if ($request->isMethod('get') && $action === 'delete_all') {
            DB::table('supplier_staging')->truncate();
            return redirect()->route('suppliers.csv', ['action'=>'list'])
                ->with('success', 'All staged rows deleted.');
        }

        $rows = DB::table('supplier_staging')->orderBy('id', 'asc')->paginate(20);
        return view('suppliers.csv-index', compact('rows'));
    }

    protected function stageCsv(string $filepath): int
    {
        $handle = fopen($filepath, 'r');
        if (!$handle) return 0;

        $header = fgetcsv($handle);
        $count = 0;
        $map = $this->detectHeaderMap($header);

        $now = now();
        while (($row = fgetcsv($handle)) !== false) {
            $data = [
                'supplier_name'   => $row[$map['supplier_name']]  ?? null,
                'company_name'    => $row[$map['company_name']]   ?? null,
                'email'           => $row[$map['email']]          ?? null,
                'address'         => $row[$map['address']]        ?? null,
                'phone_personal'  => $row[$map['phone_personal']] ?? null,
                'opening_balance' => $this->numOrNull($row[$map['opening_balance']] ?? null),
                'due_limit'       => $this->numOrNull($row[$map['due_limit']] ?? null),
                'remark'          => $row[$map['remark']]         ?? null,
                'party_type'      => $row[$map['party_type']]     ?? null,
                'bag_warehouse'   => $row[$map['bag_warehouse']]  ?? null,
                'bag_opening'     => (int)($row[$map['bag_opening']] ?? 0),
                'is_valid'        => 1,
                'created_at'      => $now,
                'updated_at'      => $now,
            ];

            DB::table('supplier_staging')->insert($data);
            $count++;
        }

        fclose($handle);
        return $count;
    }

    protected function importBatch(int $limit): int
    {
        $rows = DB::table('supplier_staging')->orderBy('id')->limit($limit)->get();
        $imported = 0;

        foreach ($rows as $r) {
            if ($this->importRow($r)) {
                $imported++;
                DB::table('supplier_staging')->where('id', $r->id)->delete();
            }
        }
        return $imported;
    }

    protected function importOne(int $id): bool
    {
        $r = DB::table('supplier_staging')->where('id', $id)->first();
        if (!$r) return false;
        $ok = $this->importRow($r);
        if ($ok) {
            DB::table('supplier_staging')->where('id', $id)->delete();
        }
        return $ok;
    }

    protected function importRow(object $r): bool
    {
        $data = [
            'supplierid'       => $this->generateSupplierId(),
            'name'             => $r->supplier_name,
            'company_name'     => $r->company_name,
            'email'            => $r->email,
            'address'          => $r->address,
            'personal_phone'   => $r->phone_personal,
            'opening_balance'  => $r->opening_balance,
            'due_limit'        => $r->due_limit,
            'remarks'          => $r->remark,
            'bag_opening'      => (int)$r->bag_opening,
            'bag_warehouse_id' => 1,
            'party_type_id'    => null,
            'created_by'       => Auth::id() ?? 1,
            'status'           => 0,
            'current_balance'  => 0.00,
        ];

        if (empty($data['personal_phone']) || empty($data['bag_warehouse_id']) || !isset($data['bag_opening'])) {
            return false;
        }

        Supplier::create($data);
        return true;
    }

    protected function detectHeaderMap(?array $header): array
    {
        $defaults = [
            'supplier_name'  => 0,
            'company_name'   => 1,
            'email'          => 2,
            'address'        => 3,
            'phone_personal' => 4,
            'opening_balance'=> 5,
            'due_limit'      => 6,
            'remark'         => 7,
            'party_type'     => 8,
            'bag_warehouse'  => 9,
            'bag_opening'    => 10,
        ];
        if (!$header) return $defaults;

        $norm = array_map(fn($h) => strtolower(trim(preg_replace('/\s+/', '_', $h))), $header);
        $want = array_keys($defaults);
        $map  = [];
        foreach ($want as $k) {
            $idx = array_search($k, $norm, true);
            $map[$k] = ($idx !== false) ? $idx : $defaults[$k];
        }
        return $map;
    }

    protected function numOrNull($v)
    {
        if ($v === null || $v === '') return null;
        return is_numeric($v) ? (float)$v : null;
    }

    protected function getPartyTypes()
    {
        return PartyType::query()
            ->when($this->hasColumn('party_types', 'status'), fn($q) => $q->where('status', 1))
            ->when($this->hasColumn('party_types', 'is_active'), fn($q) => $q->where('is_active', 1))
            ->orderBy('name')
            ->get(['id', 'name']);
    }

    protected function getBagWares()
    {
        $table = (new Warehouse)->getTable();
        return Warehouse::query()
            ->when($this->hasColumn($table, 'status'), fn($q) => $q->where('status', 1))
            ->when($this->hasColumn($table, 'is_active'), fn($q) => $q->where('is_active', 1))
            ->orderBy('name')
            ->get(['id', 'name']);
    }

    protected function hasColumn(string $table, string $column): bool
    {
        try { return Schema::hasColumn($table, $column); }
        catch (\Throwable $e) { return false; }
    }

    protected function generateSupplierId(): string
    {
        $prefix = 'Sup-' . now()->year . '-';

        $last = Supplier::where('supplierid', 'like', $prefix.'%')
                ->orderBy('supplierid', 'desc')
                ->value('supplierid');

        $n = 1;
        if ($last && preg_match('/(\d+)$/', $last, $m)) {
            $n = ((int)$m[1]) + 1;
        }

        return $prefix . str_pad((string)$n, 3, '0', STR_PAD_LEFT);
    }

    /* ========================= EXPORTS ========================= */
    public function export(Request $request)
    {
        $format = strtolower($request->get('format', 'xlsx'));   // xlsx|csv|pdf
        $q      = trim((string)$request->get('q', ''));

        $rows = Supplier::query()
            ->when($q !== '', function ($query) use ($q) {
                $query->where(function ($qb) use ($q) {
                    $qb->where('name', 'like', "%{$q}%")
                       ->orWhere('company_name', 'like', "%{$q}%")
                       ->orWhere('email', 'like', "%{$q}%")
                       ->orWhere('personal_phone', 'like', "%{$q}%");
                });
            })
            ->orderBy('id', 'desc')
            ->get([
                'supplierid','name','company_name','email','personal_phone','address',
                'due_limit','current_balance','bag_opening','remarks'
            ]);

        $filenameBase = 'suppliers_' . now()->format('Ymd_His');

        if ($format === 'csv' || $format === 'xlsx') {
            $filename = $filenameBase . ($format === 'xlsx' ? '.xlsx' : '.csv');
            $headers  = [
                'Content-Type'        => 'text/csv; charset=UTF-8',
                'Content-Disposition' => "attachment; filename=\"{$filename}\"",
            ];

            return response()->stream(function () use ($rows) {
                $out = fopen('php://output', 'w');
                fprintf($out, chr(0xEF).chr(0xBB).chr(0xBF)); // UTF-8 BOM

                fputcsv($out, [
                    'Supplier ID','Supplier Name','Company Name','Email',
                    'Phone Personal','Address','Due Limit','Current Balance','Bag Opening','Remarks'
                ]);

                foreach ($rows as $r) {
                    fputcsv($out, [
                        $r->supplierid,
                        $r->name,
                        $r->company_name,
                        $r->email,
                        $r->personal_phone,
                        $r->address,
                        number_format((float)($r->due_limit ?? 0), 2, '.', ''),
                        number_format((float)($r->current_balance ?? 0), 2, '.', ''),
                        (int)($r->bag_opening ?? 0),
                        (string)($r->remarks ?? ''),
                    ]);
                }
                fclose($out);
            }, 200, $headers);
        }

        if ($format === 'pdf') {
            try {
                if (class_exists(\Barryvdh\DomPDF\Facade\Pdf::class)) {
                    $html = $this->buildSimplePdfHtml($rows);
                    $pdf  = \Barryvdh\DomPDF\Facade\Pdf::loadHTML($html)->setPaper('a4', 'landscape');
                    return $pdf->download("{$filenameBase}.pdf");
                }
            } catch (\Throwable $e) {
                // fallback below
            }
            $request->merge(['format' => 'csv']);
            return $this->export($request);
        }

        $request->merge(['format' => 'csv']);
        return $this->export($request);
    }

    protected function buildSimplePdfHtml($rows): string
    {
        $style = <<<CSS
            <style>
              body{font-family: DejaVu Sans, sans-serif; font-size:12px;}
              table{width:100%; border-collapse:collapse}
              th,td{border:1px solid #ccc; padding:6px 8px}
              th{background:#f4f6fa; font-weight:700}
              .mono{font-variant-numeric: tabular-nums}
            </style>
        CSS;

        $thead = '<tr>
            <th>Supplier ID</th><th>Supplier Name</th><th>Company Name</th><th>Email</th>
            <th>Phone Personal</th><th>Address</th>
            <th class="mono">Due Limit</th><th class="mono">Current Balance</th>
            <th class="mono">Bag Opening</th><th>Remarks</th>
        </tr>';

        $tbody = '';
        foreach ($rows as $r) {
            $tbody .= '<tr>'.
                '<td>'.e($r->supplierid).'</td>'.
                '<td>'.e($r->name).'</td>'.
                '<td>'.e($r->company_name).'</td>'.
                '<td>'.e($r->email).'</td>'.
                '<td>'.e($r->personal_phone).'</td>'.
                '<td>'.e($r->address).'</td>'.
                '<td class="mono">'.number_format((float)($r->due_limit ?? 0),2).'</td>'.
                '<td class="mono">'.number_format((float)($r->current_balance ?? 0),2).'</td>'.
                '<td class="mono">'.(int)($r->bag_opening ?? 0).'</td>'.
                '<td>'.e($r->remarks ?? '').'</td>'.
            '</tr>';
        }

        return $style.'<h3>Suppliers</h3><table><thead>'.$thead.'</thead><tbody>'.$tbody.'</tbody></table>';
    }
}
