<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Penggajian;
use App\Models\DetailPenggajian;
use App\Models\Teknisi;
use App\Models\TarifPekerjaan;
use App\Models\Absensi;
use App\Models\Penugasan;
use App\Models\Kasbon;
use App\Exports\PenggajianExport;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;

class PenggajianController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        $query = Penggajian::with(['teknisi'])
                          ->latest('periode_tahun')
                          ->latest('periode_bulan');

        if ($request->filled('periode_bulan')) {
            $query->where('periode_bulan', $request->periode_bulan);
        }
        if ($request->filled('periode_tahun')) {
            $query->where('periode_tahun', $request->periode_tahun);
        }
        if ($request->filled('status_pembayaran')) {
            $query->where('status_pembayaran', $request->status_pembayaran);
        }
        if ($request->filled('id_teknisi')) {
            $query->where('id_teknisi', $request->id_teknisi);
        }

        if ($request->expectsJson()) {
            $penggajians = $query->get();
            $rows = $penggajians->map(function ($g) {
                return [
                    'id_penggajian'          => $g->id_penggajian,
                    'nama_teknisi'           => $g->teknisi->nama ?? 'N/A',
                    'periode_label'          => Carbon::create()->month($g->periode_bulan)->format('M') . ' ' . $g->periode_tahun,
                    'tanggal_penggajian'     => $g->tanggal_penggajian->format('d/m/Y'),
                    'jumlah_hari_kerja'      => $g->jumlah_hari_kerja,
                    'total_ongkos_pekerjaan' => $g->total_ongkos_pekerjaan,
                    'biaya_makan'            => $g->biaya_makan,
                    'total_kasbon'           => $g->total_kasbon,
                    'gaji_bersih'            => $g->gaji_bersih,
                    'status_pembayaran'      => $g->status_pembayaran,
                ];
            });
            $summary = $penggajians->count() > 0 ? [
                'total_teknisi' => $penggajians->count(),
                'total_gaji'    => $penggajians->sum('total_ongkos_pekerjaan'),
                'total_kasbon'  => $penggajians->sum('total_kasbon') + $penggajians->sum('biaya_makan'),
                'gaji_bersih'   => $penggajians->sum('gaji_bersih'),
            ] : null;
            return response()->json(['rows' => $rows, 'summary' => $summary]);
        }

        $teknisiList = Teknisi::where('status', 'aktif')->orderBy('nama')->get();
        return view('Admin.Gaji.Penggajian', compact('teknisiList'));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $teknisis = Teknisi::where('status', 'aktif')->get();
        $tarifs   = TarifPekerjaan::where('is_active', true)->get();
        return view('admin.penggajian.create', compact('teknisis', 'tarifs'));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id_teknisi'               => 'required|exists:teknisis,id_teknisi',
            'periode_bulan'            => 'required|integer|between:1,12',
            'periode_tahun'            => 'required|integer|min:2020|max:' . (date('Y') + 1),
            'tanggal_penggajian'       => 'required|date',
            'biaya_makan'              => 'nullable|numeric|min:0',
            'total_kasbon'             => 'nullable|numeric|min:0',
            'details'                  => 'required|array|min:1',
            'details.*.id_tarif'       => 'required|exists:tarif_pekerjaans,id_tarif',
            'details.*.jumlah_unit'    => 'required|integer|min:1',
            'details.*.tarif_per_unit' => 'required|numeric|min:0',
        ]);

        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        $exists = Penggajian::isPeriodeExists(
            $request->id_teknisi,
            $request->periode_bulan,
            $request->periode_tahun
        );

        if ($exists) {
            return back()->withErrors([
                'periode' => 'Penggajian untuk teknisi ini pada periode tersebut sudah ada.'
            ])->withInput();
        }

        DB::beginTransaction();
        try {
            $gaji_kotor = 0;
            foreach ($request->details as $detail) {
                $gaji_kotor += $detail['jumlah_unit'] * $detail['tarif_per_unit'];
            }

            $penggajian = Penggajian::create([
                'id_teknisi'         => $request->id_teknisi,
                'periode_bulan'      => $request->periode_bulan,
                'periode_tahun'      => $request->periode_tahun,
                'tanggal_penggajian' => $request->tanggal_penggajian,
                'jumlah_hari_kerja'  => $this->calculateHariKerja(
                    $request->id_teknisi,
                    $request->periode_bulan,
                    $request->periode_tahun
                ),
                'gaji_kotor'         => $gaji_kotor,
                'biaya_makan'        => $request->biaya_makan ?? 0,
                'total_kasbon'       => $request->total_kasbon ?? 0,
                'total_potongan'     => $request->total_kasbon ?? 0,
                'status_pembayaran'  => Penggajian::STATUS_BELUM_BAYAR,
            ]);

            foreach ($request->details as $detail) {
                DetailPenggajian::create([
                    'id_penggajian'  => $penggajian->id_penggajian,
                    'id_teknisi'     => $request->id_teknisi,
                    'id_tarif'       => $detail['id_tarif'],
                    'jumlah_unit'    => $detail['jumlah_unit'],
                    'tarif_per_unit' => $detail['tarif_per_unit'],
                ]);
            }

            DB::commit();
            return redirect()->route('penggajian.index')
                             ->with('success', 'Data penggajian berhasil dibuat.');

        } catch (\Exception $e) {
            DB::rollback();
            return back()->withErrors(['error' => 'Gagal menyimpan data penggajian.'])->withInput();
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(Penggajian $penggajian)
    {
        $penggajian->load(['teknisi', 'detailPenggajian.penugasan']);
        return view('admin.penggajian.show', compact('penggajian'));
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Penggajian $penggajian)
    {
        $penggajian->load(['teknisi', 'detailPenggajian.penugasan']);
        $teknisis = Teknisi::where('status', 'aktif')->get();
        $tarifs   = TarifPekerjaan::where('is_active', true)->get();
        return view('admin.penggajian.edit', compact('penggajian', 'teknisis', 'tarifs'));
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Penggajian $penggajian)
    {
        $validator = Validator::make($request->all(), [
            'tanggal_penggajian'       => 'required|date',
            'biaya_makan'              => 'nullable|numeric|min:0',
            'total_kasbon'             => 'nullable|numeric|min:0',
            'details'                  => 'required|array|min:1',
            'details.*.id_tarif'       => 'required|exists:tarif_pekerjaans,id_tarif',
            'details.*.jumlah_unit'    => 'required|integer|min:1',
            'details.*.tarif_per_unit' => 'required|numeric|min:0',
        ]);

        if ($validator->fails()) {
            return back()->withErrors($validator)->withInput();
        }

        DB::beginTransaction();
        try {
            $gaji_kotor = 0;
            foreach ($request->details as $detail) {
                $gaji_kotor += $detail['jumlah_unit'] * $detail['tarif_per_unit'];
            }

            $penggajian->update([
                'tanggal_penggajian'     => $request->tanggal_penggajian,
                'total_ongkos_pekerjaan' => $gaji_kotor,
                'biaya_makan'            => $request->biaya_makan ?? 0,
                'total_kasbon'           => $request->total_kasbon ?? 0,
                'total_potongan'         => $request->total_kasbon ?? 0,
            ]);

            $penggajian->detailPenggajian()->delete();

            $gajiData = $this->calculateGajiTeknisi(
                $penggajian->id_teknisi,
                $penggajian->periode_bulan,
                $penggajian->periode_tahun,
                $penggajian->tanggal_penggajian
            );

            foreach ($gajiData['details'] as $detail) {
                DetailPenggajian::create([
                    'id_penggajian'    => $penggajian->id_penggajian,
                    'id_penugasan'     => $detail['id_penugasan'],
                    'tanggal_selesai'  => $detail['tanggal_selesai'],
                    'lokasi'           => $detail['lokasi'],
                    'ongkos_penugasan' => $detail['ongkos_penugasan'],
                    'jumlah_tim'       => $detail['jumlah_tim'],
                    'bagian_ongkos'    => $detail['bagian_ongkos'],
                ]);
            }

            DB::commit();
            return redirect()->route('penggajian.index')
                             ->with('success', 'Data penggajian berhasil diperbarui.');

        } catch (\Exception $e) {
            DB::rollback();
            return back()->withErrors(['error' => 'Gagal memperbarui data penggajian.'])->withInput();
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Penggajian $penggajian)
    {
        try {
            DB::beginTransaction();
            $penggajian->detailPenggajian()->delete();
            $penggajian->delete();
            DB::commit();

            return response()->json(['success' => true, 'message' => 'Data penggajian berhasil dihapus.']);
        } catch (\Exception $e) {
            DB::rollback();
            return response()->json(['success' => false, 'message' => 'Gagal menghapus data penggajian.'], 500);
        }
    }

    /**
     * Hitung gaji untuk periode tertentu.
     *
     * Tambahan parameter:
     *   force_recalculate (boolean, default false)
     *     → Jika true, data penggajian yang sudah ada akan dihapus dan dihitung ulang.
     *       Gunakan ini ketika ada penugasan baru yang selesai SETELAH gaji di-generate,
     *       sehingga semua anggota tim (termasuk yang tidak jadi teknisi utama) ikut terhitung.
     *     → Jika false (default), teknisi yang sudah punya data di periode itu akan di-skip.
     *
     * CATATAN: Penggajian yang sudah berstatus 'sudah_bayar' TIDAK akan di-recalculate
     * meski force_recalculate = true, untuk mencegah perubahan data yang sudah dibayar.
     */
    public function hitungGaji(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'id_teknisi'         => 'nullable|exists:teknisis,id_teknisi',
            'periode_bulan'      => 'required|integer|between:1,12',
            'periode_tahun'      => 'required|integer|min:2020|max:' . (date('Y') + 1),
            'tanggal_penggajian' => 'required|date',
            'include_kasbon'     => 'boolean',
            'force_recalculate'  => 'boolean',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Data tidak valid. ' . implode(' ', $validator->errors()->all()),
                'errors'  => $validator->errors()
            ], 422);
        }

        try {
            DB::beginTransaction();

            $periode_bulan      = $request->periode_bulan;
            $periode_tahun      = $request->periode_tahun;
            $tanggal_penggajian = $request->tanggal_penggajian
                ?? Carbon::create($periode_tahun, $periode_bulan)->endOfMonth()->format('Y-m-d');
            $include_kasbon     = $request->boolean('include_kasbon', true);
            $force_recalculate  = $request->boolean('force_recalculate', false);
            $id_teknisi         = $request->id_teknisi;

            if ($id_teknisi) {
                $teknisis = Teknisi::where('id_teknisi', $id_teknisi)->where('status', 'aktif')->get();
            } else {
                $teknisis = Teknisi::where('status', 'aktif')->get();
            }

            $created_count     = 0;
            $skipped_count     = 0;
            $recalculated_count = 0;

            foreach ($teknisis as $teknisi) {
                // Cek apakah sudah ada penggajian untuk periode ini
                $existingPenggajian = Penggajian::where('id_teknisi', $teknisi->id_teknisi)
                    ->where('periode_bulan', $periode_bulan)
                    ->where('periode_tahun', $periode_tahun)
                    ->first();

                if ($existingPenggajian) {
                    if (!$force_recalculate) {
                        // Tidak force → skip seperti perilaku lama
                        $skipped_count++;
                        continue;
                    }

                    // Sudah dibayar → jangan recalculate, lindungi data yang sudah final
                    if ($existingPenggajian->status_pembayaran === Penggajian::STATUS_SUDAH_BAYAR) {
                        $skipped_count++;
                        continue;
                    }

                    // Force recalculate → hapus detail dan penggajian lama, hitung ulang
                    $existingPenggajian->detailPenggajian()->delete();
                    $existingPenggajian->delete();
                    $recalculated_count++;
                }

                $gajiData = $this->calculateGajiTeknisi(
                    $teknisi->id_teknisi,
                    $periode_bulan,
                    $periode_tahun,
                    $tanggal_penggajian,
                    $include_kasbon
                );

                if ($gajiData['gaji_kotor'] > 0 || $gajiData['biaya_makan'] > 0 || !empty($gajiData['details'])) {
                    $total_penugasan = !empty($gajiData['details']) ? count($gajiData['details']) : 0;

                    $penggajian = Penggajian::create([
                        'id_teknisi'               => $teknisi->id_teknisi,
                        'periode_bulan'            => $periode_bulan,
                        'periode_tahun'            => $periode_tahun,
                        'tanggal_penggajian'       => $tanggal_penggajian,
                        'jumlah_hari_kerja'        => $gajiData['jumlah_hari_kerja'],
                        'jumlah_penugasan_selesai' => $total_penugasan,
                        'total_ongkos_pekerjaan'   => $gajiData['gaji_kotor'],
                        'biaya_makan'              => $gajiData['biaya_makan'],
                        'total_kasbon'             => $gajiData['total_kasbon'],
                        'total_potongan'           => $gajiData['total_kasbon'],
                        'gaji_bersih'              => $gajiData['gaji_kotor'] - $gajiData['biaya_makan'] - $gajiData['total_kasbon'],
                        'status_pembayaran'        => Penggajian::STATUS_BELUM_BAYAR,
                    ]);

                    foreach ($gajiData['details'] as $detail) {
                        DetailPenggajian::create([
                            'id_penggajian'    => $penggajian->id_penggajian,
                            'id_penugasan'     => $detail['id_penugasan'],
                            'tanggal_selesai'  => $detail['tanggal_selesai'],
                            'lokasi'           => $detail['lokasi'],
                            'ongkos_penugasan' => $detail['ongkos_penugasan'],
                            'jumlah_tim'       => $detail['jumlah_tim'],
                            'bagian_ongkos'    => $detail['bagian_ongkos'],
                            'rincian_pekerjaan'=> $detail['rincian_pekerjaan'] ?? null,
                        ]);
                    }

                    $created_count++;
                }
            }

            DB::commit();

            $message = "Berhasil menghitung gaji untuk {$created_count} teknisi.";
            if ($recalculated_count > 0) {
                $message .= " {$recalculated_count} teknisi dihitung ulang.";
            }
            if ($skipped_count > 0) {
                $message .= " {$skipped_count} teknisi dilewati (sudah ada data atau sudah dibayar).";
            }

            return response()->json([
                'success' => true,
                'message' => $message,
                'data'    => [
                    'created'      => $created_count,
                    'recalculated' => $recalculated_count,
                    'skipped'      => $skipped_count,
                ]
            ]);

        } catch (\Exception $e) {
            DB::rollback();
            return response()->json([
                'success' => false,
                'message' => 'Gagal menghitung gaji: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Hitung ulang penggajian untuk satu teknisi tertentu.
     *
     * Endpoint: POST /penggajian/{penggajian}/recalculate
     *
     * Berguna ketika:
     * - Ada penugasan tim yang baru selesai setelah gaji di-generate
     * - Anggota tim yang tidak jadi teknisi utama tidak muncul di rincian
     * - Data detail penggajian tidak lengkap / tidak sesuai
     *
     * Penggajian yang sudah 'sudah_bayar' tidak bisa di-recalculate.
     */
    public function recalculate(Penggajian $penggajian)
    {
        try {
            DB::beginTransaction();

            // Hapus detail lama
            $penggajian->detailPenggajian()->delete();

            // Jika sudah lunas, kita tidak ingin menarik data kasbon baru dari database 
            // karena kasbon aslinya mungkin sudah berstatus lunas. 
            // Kita gunakan nilai total_kasbon yang sudah tersimpan di record ini.
            $isPaid = $penggajian->status_pembayaran === Penggajian::STATUS_SUDAH_BAYAR;

            $gajiData = $this->calculateGajiTeknisi(
                $penggajian->id_teknisi,
                $penggajian->periode_bulan,
                $penggajian->periode_tahun,
                $penggajian->tanggal_penggajian,
                !$isPaid // includeKasbon hanya jika belum bayar
            );

            $total_penugasan = count($gajiData['details']);

            // Update header penggajian
            $penggajian->update([
                'jumlah_hari_kerja'        => $gajiData['jumlah_hari_kerja'],
                'jumlah_penugasan_selesai' => $total_penugasan,
                'total_ongkos_pekerjaan'   => $gajiData['gaji_kotor'],
                'biaya_makan'              => $gajiData['biaya_makan'],
                'total_kasbon'             => $isPaid ? $penggajian->total_kasbon : $gajiData['total_kasbon'],
                'total_potongan'           => $isPaid ? $penggajian->total_kasbon : $gajiData['total_kasbon'],
                'gaji_bersih'              => $gajiData['gaji_kotor'] - $gajiData['biaya_makan'] - ($isPaid ? $penggajian->total_kasbon : $gajiData['total_kasbon']),
            ]);

            // Insert detail baru
            foreach ($gajiData['details'] as $detail) {
                DetailPenggajian::create([
                    'id_penggajian'    => $penggajian->id_penggajian,
                    'id_penugasan'     => $detail['id_penugasan'],
                    'tanggal_selesai'  => $detail['tanggal_selesai'],
                    'lokasi'           => $detail['lokasi'],
                    'ongkos_penugasan' => $detail['ongkos_penugasan'],
                    'jumlah_tim'       => $detail['jumlah_tim'],
                    'bagian_ongkos'    => $detail['bagian_ongkos'],
                    'rincian_pekerjaan'=> $detail['rincian_pekerjaan'] ?? null,
                ]);
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => "Penggajian berhasil dihitung ulang. Ditemukan {$total_penugasan} penugasan.",
                'data'    => [
                    'total_penugasan'      => $total_penugasan,
                    'total_ongkos'         => $gajiData['gaji_kotor'],
                    'jumlah_hari_kerja'    => $gajiData['jumlah_hari_kerja'],
                    'biaya_makan'          => $gajiData['biaya_makan'],
                    'total_kasbon'         => $gajiData['total_kasbon'],
                ]
            ]);

        } catch (\Exception $e) {
            DB::rollback();
            return response()->json([
                'success' => false,
                'message' => 'Gagal menghitung ulang: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get detail penggajian for modal
     */
    public function detail(Penggajian $penggajian)
    {
        $penggajian->load(['teknisi', 'detailPenggajian.penugasan']);
        return view('Admin.Gaji.detail_penggajian', compact('penggajian'));
    }

    /**
     * Process payment for specific penggajian
     */
    public function prosesPembayaran(Penggajian $penggajian)
    {
        try {
            if ($penggajian->isPaid()) {
                return response()->json(['success' => false, 'message' => 'Gaji sudah dibayar sebelumnya.']);
            }

            $penggajian->markAsPaid();

            // ── LOGIKA PELUNASAN KASBON (DENGAN SISTEM CICILAN/PARTIAL) ──
            $sisaPotongan = (float) $penggajian->total_kasbon;

            if ($sisaPotongan > 0) {
                // Ambil semua kasbon belum lunas, urutkan dari yang paling lama
                $kasbons = Kasbon::where('id_teknisi', $penggajian->id_teknisi)
                    ->where('status', 'belum_lunas')
                    ->whereDate('tanggal_kasbon', '<=', $penggajian->tanggal_penggajian)
                    ->orderBy('tanggal_kasbon', 'asc')
                    ->get();

                foreach ($kasbons as $kb) {
                    if ($sisaPotongan <= 0) break;

                    $jumlahKb = (float) $kb->jumlah_kasbon;

                    if ($sisaPotongan >= $jumlahKb) {
                        // Kasbon ini terbayar penuh
                        $kb->update(['status' => 'lunas']);
                        $sisaPotongan -= $jumlahKb;
                    } else {
                        // Kasbon ini terbayar sebagian (CICILAN)
                        // 1. Kurangi nilai kasbon lama
                        $kb->update([
                            'jumlah_kasbon' => $jumlahKb - $sisaPotongan
                        ]);
                        
                        // 2. Buat record baru untuk bagian yang sudah lunas (untuk histori)
                        $newLunas = $kb->replicate();
                        $newLunas->jumlah_kasbon = $sisaPotongan;
                        $newLunas->status = 'lunas';
                        $newLunas->keperluan = $kb->keperluan . ' (Cicilan via Gaji ' . $penggajian->formatted_periode . ')';
                        $newLunas->save();

                        $sisaPotongan = 0;
                    }
                }
            }

            return response()->json([
                'success' => true,
                'message' => 'Pembayaran berhasil diproses dan kasbon telah dilunasi.'
            ]);

        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal memproses pembayaran.'], 500);
        }
    }

    public function updateKasbon(Request $request, Penggajian $penggajian)
    {
        try {
            $rawInput = $request->input('total_kasbon', 0);
            $cleanInput = preg_replace('/[^0-9]/', '', $rawInput);
            $newKasbon = (float) $cleanInput;

            if ($newKasbon < 0) {
                return response()->json(['success' => false, 'message' => 'Nominal kasbon tidak boleh negatif.'], 422);
            }

            $penggajian->update([
                'total_kasbon'   => $newKasbon,
                'total_potongan' => $newKasbon,
                'gaji_bersih'    => $penggajian->total_ongkos_pekerjaan - $penggajian->biaya_makan - $newKasbon,
            ]);

            return response()->json([
                'success' => true,
                'message' => 'Potongan kasbon berhasil diubah menjadi Rp ' . number_format($newKasbon, 0, ',', '.') . '. Gaji bersih akan dihitung ulang otomatis.'
            ]);

        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal mengubah potongan: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Update food deduction amount manually.
     * Allows mandor to waive food costs for bereavement or emergencies.
     */
    public function updateMakan(Request $request, Penggajian $penggajian)
    {
        try {
            $rawInput = $request->input('biaya_makan', 0);
            $cleanInput = preg_replace('/[^0-9]/', '', $rawInput);
            $newMakan = (float) $cleanInput;

            if ($newMakan < 0) {
                return response()->json(['success' => false, 'message' => 'Nominal biaya makan tidak boleh negatif.'], 422);
            }

            $penggajian->update([
                'biaya_makan' => $newMakan,
                'gaji_bersih' => $penggajian->total_ongkos_pekerjaan - $newMakan - $penggajian->total_kasbon,
            ]);

            return response()->json([
                'success' => true,
                'message' => 'Biaya makan berhasil diubah menjadi Rp ' . number_format($newMakan, 0, ',', '.') . '.'
            ]);

        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal mengubah biaya makan: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Process all unpaid payments
     */
    public function prosesSemuaPembayaran()
    {
        try {
            $unpaidCount = Penggajian::belumBayar()->count();

            if ($unpaidCount == 0) {
                return response()->json(['success' => false, 'message' => 'Tidak ada pembayaran yang perlu diproses.']);
            }

            Penggajian::belumBayar()->update(['status_pembayaran' => Penggajian::STATUS_SUDAH_BAYAR]);

            return response()->json([
                'success' => true,
                'message' => "Berhasil memproses pembayaran untuk {$unpaidCount} teknisi."
            ]);

        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal memproses pembayaran.'], 500);
        }
    }

    /**
     * Generate slip gaji
     */
    public function slip(Penggajian $penggajian)
    {
        $penggajian->load(['teknisi', 'detailPenggajian.penugasan']);
        return view('admin.Gaji.slip_penggajian', compact('penggajian'));
    }

    /**
     * Export to Excel
     */
    public function export(Request $request)
    {
        $query = Penggajian::with(['teknisi']);

        if ($request->filled('periode_bulan'))     $query->where('periode_bulan', $request->periode_bulan);
        if ($request->filled('periode_tahun'))     $query->where('periode_tahun', $request->periode_tahun);
        if ($request->filled('status_pembayaran')) $query->where('status_pembayaran', $request->status_pembayaran);

        $penggajians = $query->get();
        return Excel::download(new PenggajianExport($penggajians), 'penggajian_' . date('Y-m-d') . '.xlsx');
    }

    // =====================================================================
    // PRIVATE HELPERS
    // =====================================================================

    /**
     * Calculate gaji untuk teknisi tertentu.
     *
     * Mencari semua penugasan di mana teknisi ini terlibat, baik sebagai:
     *   (a) Teknisi utama (kolom id_teknisi di tabel penugasans), ATAU
     *   (b) Anggota tim (tabel tim_teknisi_penugasans) dengan status_kehadiran = hadir
     *
     * Ongkos dibagi rata berdasarkan jumlah anggota tim yang hadir.
     * Contoh: ongkos Rp 50.000, tim 2 orang → masing-masing Rp 25.000
     */
    private function calculateGajiTeknisi($idTeknisi, $bulan, $tahun, $tanggalLimit = null, $includeKasbon = true)
    {
        $jumlah_hari_kerja = Absensi::where('id_teknisi', $idTeknisi)
                                    ->whereMonth('tanggal', $bulan)
                                    ->whereYear('tanggal', $tahun)
                                    ->where('status', 'hadir')
                                    ->count();

        // Cari semua penugasan yang melibatkan teknisi ini di bulan/tahun tsb
        $penugasans = Penugasan::where(function ($q) use ($idTeknisi) {
                            // (a) Teknisi utama penugasan
                            $q->where('id_teknisi', $idTeknisi)
                            // (b) Anggota tim yang hadir
                              ->orWhereHas('timTeknisi', function ($sq) use ($idTeknisi) {
                                  $sq->where('id_teknisi', $idTeknisi)
                                     ->where('status_kehadiran', 'hadir');
                              });
                        })
                        ->where('status_pekerjaan', 'selesai')
                        ->where(function ($q) use ($bulan, $tahun) {
                            // Filter berdasarkan bulan selesai
                            // Prioritas: tanggal_diselesaikan, fallback ke updated_at
                            $q->where(function ($q2) use ($bulan, $tahun) {
                                $q2->whereNotNull('tanggal_diselesaikan')
                                   ->whereMonth('tanggal_diselesaikan', $bulan)
                                   ->whereYear('tanggal_diselesaikan', $tahun);
                            })->orWhere(function ($q2) use ($bulan, $tahun) {
                                $q2->whereNull('tanggal_diselesaikan')
                                   ->whereMonth('updated_at', $bulan)
                                   ->whereYear('updated_at', $tahun);
                            });
                        })
                        ->with(['items.tarif', 'timTeknisi'])
                        ->get();

        $gaji_kotor     = 0;
        $list_penugasan = [];

        foreach ($penugasans as $penugasan) {
            // Hitung jumlah anggota tim yang hadir
            // Jika tidak ada record tim → teknisi kerja sendiri → jumlah = 1
            $jumlahHadir = $penugasan->countTimHadir();
            if ($jumlahHadir === 0) {
                $jumlahHadir = 1;
            }

            // Hitung total ongkos dari penugasan_items
            $totalOngkosTugas = 0;
            if ($penugasan->items->count() > 0) {
                foreach ($penugasan->items as $item) {
                    $itemTotal = (float) $item->total_nilai_pekerjaan;
                    if ($itemTotal <= 0) {
                        $itemTotal = $this->calculatePenugasanItemValue($item);
                    }
                    $totalOngkosTugas += $itemTotal;
                }
            }

            // Fallback: ambil dari total_nilai_pekerjaan penugasan induk atau tarif
            if ($totalOngkosTugas <= 0) {
                $totalOngkosTugas = $this->calculatePenugasanValue($penugasan);
            }

            // Lewati jika ongkos masih 0 setelah semua fallback
            if ($totalOngkosTugas <= 0) {
                continue;
            }

            // Bagian ongkos = total ongkos dibagi jumlah anggota tim yang hadir
            $bagianOngkos = $totalOngkosTugas / $jumlahHadir;
            $gaji_kotor  += $bagianOngkos;

            $list_penugasan[] = [
                'id_penugasan'     => $penugasan->id_penugasan,
                'tanggal_selesai'  => $penugasan->tanggal_diselesaikan ?? $penugasan->tanggal_diberikan,
                'lokasi'           => $penugasan->alamat_lokasi
                                        ?? $penugasan->lokasi_pekerjaan
                                        ?? '-',
                'ongkos_penugasan' => $totalOngkosTugas,
                'jumlah_tim'       => $jumlahHadir,
                'bagian_ongkos'    => $bagianOngkos,
                'rincian_pekerjaan'=> $this->generateRincianLabel($penugasan),
            ];
        }

        $biaya_makan  = $jumlah_hari_kerja * 25000;
        $total_kasbon = 0;

        if ($includeKasbon) {
            $queryKasbon = Kasbon::where('id_teknisi', $idTeknisi)
                                  ->where('status', 'belum_lunas');
            
            if ($tanggalLimit) {
                $queryKasbon->whereDate('tanggal_kasbon', '<=', $tanggalLimit);
            }
            
            $total_kasbon = $queryKasbon->sum('jumlah_kasbon');
        }

        return [
            'jumlah_hari_kerja' => $jumlah_hari_kerja,
            'gaji_kotor'        => $gaji_kotor,
            'biaya_makan'       => $biaya_makan,
            'total_kasbon'      => $total_kasbon,
            'details'           => $list_penugasan,
        ];
    }

    /**
     * Calculate hari kerja dari absensi
     */
    private function calculateHariKerja($idTeknisi, $bulan, $tahun)
    {
        return Absensi::where('id_teknisi', $idTeknisi)
                      ->whereMonth('tanggal', $bulan)
                      ->whereYear('tanggal', $tahun)
                      ->where('status', 'hadir')
                      ->count();
    }

    /**
     * Calculate nilai penugasan dengan fallback ke tarif
     */
    private function calculatePenugasanValue($penugasan): float
    {
        if ($penugasan->total_nilai_pekerjaan > 0) {
            return (float) $penugasan->total_nilai_pekerjaan;
        }

        $tarif = $penugasan->tarif;
        if (!$tarif) {
            $query = TarifPekerjaan::where('jenis_pekerjaan', $penugasan->jenis_pekerjaan)
                                   ->where('is_active', true);
            if ($penugasan->dimensi_pipa) {
                $query->where('dimensi_pipa', $penugasan->dimensi_pipa);
            }
            $tarif = $query->first();
        }

        if (!$tarif) return 0;

        if ($penugasan->jarak_meter > 0 && $tarif->tarif_per_meter) {
            return (float) $tarif->tarif_per_meter * (float) $penugasan->jarak_meter;
        }
        if ($penugasan->jumlah_unit > 0 && $tarif->tarif_per_unit) {
            return (float) $tarif->tarif_per_unit * (int) $penugasan->jumlah_unit;
        }
        if ($penugasan->jumlah_titik > 0 && $tarif->tarif_per_unit) {
            return (float) $tarif->tarif_per_unit * (int) $penugasan->jumlah_titik;
        }

        return (float) ($tarif->tarif_per_unit ?? $tarif->tarif_per_meter ?? 0);
    }

    /**
     * Generate label rincian pekerjaan untuk slip gaji
     */
    private function generateRincianLabel($penugasan): string
    {
        $rincian = [];

        if ($penugasan->items && $penugasan->items->count() > 0) {
            foreach ($penugasan->items as $item) {
                $detail = $item->jenis_pekerjaan;
                if ($item->jarak_meter > 0) {
                    $detail .= " ({$item->jarak_meter}m)";
                } elseif ($item->jumlah_unit > 0) {
                    $detail .= " ({$item->jumlah_unit} Unit)";
                } elseif ($item->jumlah_titik > 0) {
                    $detail .= " ({$item->jumlah_titik} Titik)";
                }
                $rincian[] = $detail;
            }
        } else {
            // Legacy: penugasan belum punya penugasan_items
            if ($penugasan->jarak_meter > 0) {
                $rincian[] = "{$penugasan->jarak_meter} Meter";
            } elseif ($penugasan->jumlah_unit > 0) {
                $rincian[] = "{$penugasan->jumlah_unit} Unit";
            } else {
                $rincian[] = "Borongan";
            }
        }

        return implode(', ', $rincian);
    }

    /**
     * Calculate nilai untuk setiap PenugasanItem
     */
    private function calculatePenugasanItemValue($item): float
    {
        if ($item->total_nilai_pekerjaan > 0) {
            return (float) $item->total_nilai_pekerjaan;
        }

        $tarif = $item->tarif;
        if (!$tarif) {
            $query = TarifPekerjaan::where('jenis_pekerjaan', $item->jenis_pekerjaan)
                                   ->where('is_active', true);
            if ($item->dimensi_pipa) {
                $query->where('dimensi_pipa', $item->dimensi_pipa);
            }
            $tarif = $query->first();
        }

        if (!$tarif) return 0;

        if ($item->jarak_meter > 0 && $tarif->tarif_per_meter) {
            return (float) $tarif->tarif_per_meter * (float) $item->jarak_meter;
        }
        if ($item->jumlah_unit > 0 && $tarif->tarif_per_unit) {
            return (float) $tarif->tarif_per_unit * (int) $item->jumlah_unit;
        }
        if ($item->jumlah_titik > 0 && $tarif->tarif_per_unit) {
            return (float) $tarif->tarif_per_unit * (int) $item->jumlah_titik;
        }

        return (float) ($tarif->tarif_per_unit ?? $tarif->tarif_per_meter ?? 0);
    }
}