<?php

namespace App\Services;

use Illuminate\Support\Facades\DB;
use Exception;

class MaintenanceService
{
    /**
     * Generate maintenance bills for a society for a specific month.
     * Uses atomic transaction.
     */
    public function generateBills($societyId, $billingMonth)
    {
        return DB::transaction(function () use ($societyId, $billingMonth) {
            // Get ALL units
            $units = DB::table('units')
                ->where('society_id', $societyId)
                ->get();

            // Get existing bill unit_ids for this month to avoid duplicates
            $existingUnitIds = DB::table('maintenance_bills')
                ->where('society_id', $societyId)
                ->where('billing_month', $billingMonth)
                ->pluck('unit_id')
                ->toArray();

            $billsToInsert = [];
            $now = now();

            foreach ($units as $unit) {
                // Skip if bill already exists
                if (in_array($unit->id, $existingUnitIds)) {
                    continue;
                }

                // Vacant units should show 0 charge.
                $amount = ($unit->status === 'vacant') ? 0 : $unit->monthly_maintenance;

                $billsToInsert[] = [
                    'society_id' => $societyId,
                    'unit_id' => $unit->id,
                    'billing_month' => $billingMonth,
                    'amount' => $amount,
                    'status' => 'pending',
                    'created_at' => $now,
                    'updated_at' => $now
                ];
            }

            if (!empty($billsToInsert)) {
                // Chunk inserts to avoid placeholder limits (though unlikely with simple data)
                foreach (array_chunk($billsToInsert, 100) as $chunk) {
                    DB::table('maintenance_bills')->insert($chunk);
                }
            }

            return count($billsToInsert);
        });
    }

    /**
     * Record a payment for a specific bill.
     * Uses atomic transaction to ensure Ledger matches Bill status.
     */
    public function recordPayment($billId, $societyId)
    {
        return DB::transaction(function () use ($billId, $societyId) {
            // Get the bill (locked for update to prevent race conditions)
            $bill = DB::table('maintenance_bills')
                ->where('id', $billId)
                ->where('society_id', $societyId)
                ->lockForUpdate()
                ->first();

            if (!$bill) {
                throw new Exception('Bill not found or unauthorized');
            }

            if ($bill->status === 'paid') {
                throw new Exception('Bill already marked as paid');
            }

            // Get unit details for description
            $unit = DB::table('units')->where('id', $bill->unit_id)->first();

            // Create Finance ledger entry (credit = income)
            $ledgerId = DB::table('account_ledgers')->insertGetId([
                'society_id' => $societyId,
                'type' => 'credit',
                'amount' => $bill->amount,
                'category' => 'Maintenance Collection',
                'description' => "Maintenance payment for Unit {$unit->unit_number} - {$bill->billing_month}",
                'transaction_date' => now()->toDateString(),
                'created_at' => now(),
                'updated_at' => now()
            ]);

            // Update bill status
            DB::table('maintenance_bills')
                ->where('id', $billId)
                ->update([
                    'status' => 'paid',
                    'paid_at' => now(),
                    'ledger_entry_id' => $ledgerId,
                    'updated_at' => now()
                ]);

            return $ledgerId;
        });
    }
}
