<?php

namespace App\Services;

use App\Models\PengajuanUkt;
use App\Models\Kriteria;
use App\Models\HasilPenilaian;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Exception;

class SawCalculationService
{
    protected $kriteria;

    public function __construct()
    {
        $this->kriteria = Kriteria::with('subKriteria')->orderBy('id')->get();

        if ($this->kriteria->isEmpty()) {
            throw new Exception('Tidak ada kriteria untuk perhitungan');
        }
    }

    public function calculate(PengajuanUkt $pengajuan): array
    {
        // Cek apakah total bobot valid (== 1)
        $totalBobot = $this->kriteria->sum('bobot');
        if (abs($totalBobot - 1) > 0.0001) {
            throw new Exception("Total bobot saat ini adalah ...");
        }

        DB::beginTransaction();

        try {
            if ($pengajuan->status_validasi !== 'valid') {
                throw new Exception("Pengajuan belum divalidasi");
            }

            if ($pengajuan->details->isEmpty()) {
                throw new Exception("Data detail pengajuan tidak lengkap");
            }

            // 1. Decision Matrix
            $decisionMatrix = $this->buildDecisionMatrix($pengajuan);
            
            // 2. Normalized Matrix
            $normalizedMatrix = $this->normalizeMatrix($decisionMatrix);
            
            // 3. Preference Value
            $preferenceValue = $this->calculatePreferenceValue($normalizedMatrix);
            
            // 4. Recommendation
             $recommendation = $this->determineRecommendation($pengajuan->jenis_pengajuan, $preferenceValue);

            // 5. Save Result
            $this->saveResult($pengajuan, $preferenceValue, $recommendation);

        DB::commit();

        return [
            'decision_matrix' => $decisionMatrix,
            'normalized_matrix' => $normalizedMatrix,
            'preference_value' => $preferenceValue,
            'recommendation' => $recommendation,
        ];

    } catch (Exception $e) {
        DB::rollBack();
        Log::error("Error pada perhitungan SAW: " . $e->getMessage());
        throw $e;
    }
}

protected function determineRecommendation(string $jenisPengajuan, float $preferenceValue): string
{
    if ($jenisPengajuan === 'penurunan') {
        return ($preferenceValue >= 0.65) ? 'Dapat Penurunan UKT' : 'UKT Tetap';
    } 
    elseif ($jenisPengajuan === 'pengangsuran') {
        return ($preferenceValue >= 0.75) ? 'Dapat Pengangsuran UKT' : 'Tidak Dapat Mengangsur';
    }
    return 'UKT Tetap'; 
} 

    public function processBatch(array $pengajuanIds): array
    {
        $successCount = 0;
        $errorCount = 0;
        $errors = [];

        foreach ($pengajuanIds as $id) {
            try {
                $pengajuan = PengajuanUkt::findOrFail($id);
                $this->calculate($pengajuan);
                $successCount++;
            } catch (Exception $e) {
                $errorCount++;
                $errors[$id] = $e->getMessage();
                Log::error("Gagal memproses pengajuan ID {$id}: " . $e->getMessage());
            }
        }

        return [
            'status' => $errorCount === 0 ? 'success' : ($successCount > 0 ? 'partial' : 'failed'),
            'message' => "Berhasil memproses {$successCount} dari " . count($pengajuanIds) . " pengajuan",
            'success_count' => $successCount,
            'error_count' => $errorCount,
            'errors' => $errors
        ];
    }

    protected function buildDecisionMatrix(PengajuanUkt $pengajuan): array
{
    $decisionMatrix = [];
    
    foreach ($this->kriteria as $kriteria) {
        $detail = $pengajuan->details->firstWhere('kriteria_id', $kriteria->id);
        if (!$detail) {
            Log::error("Missing detail for kriteria: {$kriteria->nama_kriteria}");
            continue;
        }

        $sub = $kriteria->subKriteria->firstWhere('id', $detail->sub_kriteria_id);
        if (!$sub) {
            Log::error("Missing subkriteria for detail: {$detail->id}");
            continue;
        }

        $decisionMatrix[$kriteria->id] = $sub->nilai;
    }

    if (count($decisionMatrix) !== count($this->kriteria)) {
        throw new Exception("Data kriteria tidak lengkap");
    }

    return $decisionMatrix;
}

    protected function normalizeMatrix(array $decisionMatrix): array
{
    $normalizedMatrix = [];

    foreach ($this->kriteria as $kriteria) {
        $nilai = $decisionMatrix[$kriteria->id];
        $allNilai = $kriteria->subKriteria->pluck('nilai')->toArray();

        if (empty($allNilai)) {
            throw new Exception("Subkriteria untuk kriteria ID {$kriteria->id} kosong");
        }

        if (strtolower($kriteria->attribut) === 'benefit') {
            $max = max($allNilai);
            $value = $max != 0 ? ($nilai / $max) : 0;
        } else { // COST
            $min = min($allNilai);
            $value = $nilai != 0 ? ($min / $nilai) : 0;
        }

        $normalizedMatrix[$kriteria->id] = $value;
    }
    
    return $normalizedMatrix;
}


    protected function calculatePreferenceValue(array $normalizedMatrix): float
{
    $preferenceValue = 0;

    foreach ($this->kriteria as $kriteria) {
        $bobot = $kriteria->bobot;
        $nilaiNormalisasi = $normalizedMatrix[$kriteria->id];

        $preferenceValue += $bobot * $nilaiNormalisasi;
    }

return round($preferenceValue, 5, PHP_ROUND_HALF_EVEN);
}
    protected function saveResult(PengajuanUkt $pengajuan, float $preferenceValue, string $recommendation): void
    {
        HasilPenilaian::updateOrCreate(
            ['pengajuan_id' => $pengajuan->id], 
            [
                'nilai_preferensi' => $preferenceValue,
                'rekomendasi_ukt' => $recommendation, 
                'keterangan' => null, 
                'processed_by' => auth()->id(), 
            ]
        );
    }

    public function prosesPerhitunganLengkap(array $pengajuanIds): array
    {
        return $this->processBatch($pengajuanIds);
    }

    public function getCalculationDetails($pengajuanId)
{
    $pengajuan = PengajuanUkt::with('details.subKriteria')->findOrFail($pengajuanId);
    
    // Rebuild the calculation to ensure consistency
    $decisionMatrix = $this->buildDecisionMatrix($pengajuan);
    $normalizedMatrix = $this->normalizeMatrix($decisionMatrix);
    $preferenceValue = $this->calculatePreferenceValue($normalizedMatrix);
    
    return [
        'decision_matrix' => $decisionMatrix,
        'normalized_matrix' => $normalizedMatrix,
        'preference_value' => $pengajuan->hasilPenilaian->nilai_preferensi,
        'recommendation' => $pengajuan->hasilPenilaian->rekomendasi_ukt,
    ];
}
}