<?php

namespace App\Exports;

use App\Models\User;
use App\Models\DataPenjualan;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Illuminate\Support\Collection;

class DataPenjualanRekapExport implements WithMultipleSheets
{
    /**
     * Mengatur pembagian sheet (lembar kerja) di dalam file Excel.
     */
    public function sheets(): array
    {
        $sheets = [];
        // Mengambil semua data pengguna dengan peran 'user' (pangkalan)
        $pangkalanList = User::where(['role' => 'user'])->get();

        // Sheet 1: Membuat halaman ringkasan utama sebagai pusat kontrol evaluasi agen
        $sheets[] = new RingkasanEvaluasiAgenSheet($pangkalanList);

        // Sheet 2 dan seterusnya: Membuat halaman detail laporan untuk tiap pangkalan
        foreach ($pangkalanList as $pangkalan) {
            $sheets[] = new PangkalanSalesSheet($pangkalan);
        }

        return $sheets;
    }
}

class RingkasanEvaluasiAgenSheet implements FromCollection, WithTitle, WithHeadings, WithStyles, ShouldAutoSize, WithEvents
{
    private Collection $pangkalanList;

    public function __construct(Collection $pangkalanList)
    {
        $this->pangkalanList = $pangkalanList;
    }

    /**
     * Mengatur nama dari sheet pertama.
     */
    public function title(): string
    {
        return 'Pusat Pantauan Agen';
    }

    /**
     * Memproses data matriks evaluasi seluruh pangkalan untuk ditampilkan di tabel utama.
     */
    public function collection(): Collection
    {
        Carbon::setLocale('id');
        $summaryData = collect();

        foreach ($this->pangkalanList as $index => $pangkalan) {
            // Cara mengambil data: Total penjualan dihitung per bulan dari data transaksi riil di database
            $monthlyData = DataPenjualan::where(['user_id' => $pangkalan->id])
                ->select(DB::raw("DATE_FORMAT(tanggal, '%Y-%m') as bulan"), DB::raw("SUM(jumlah) as total"))
                ->groupBy('bulan')
                ->get();

            // Jika pangkalan belum memiliki histori transaksi, lewati ke pangkalan berikutnya
            if ($monthlyData->isEmpty()) {
                continue;
            }

            $totals = $monthlyData->pluck('total');
            
            // CARA KELOLA STATISTIK 1: Mencari nilai rata-rata penjualan per bulan
            $average = $totals->avg();
            
            // CARA KELOLA STATISTIK 2: Mencari nilai simpangan baku (Standar Deviasi)
            // Digunakan untuk melihat seberapa jauh jarak naik-turunnya angka penjualan dari nilai rata-rata
            $variance = 0;
            foreach ($totals as $t) {
                $variance += pow(($t - $average), 2);
            }
            $stdDev = sqrt($variance / $totals->count());

            // CARA KELOLA STATISTIK 3: Menghitung nilai Koefisien Variasi (CV)
            // Rumus: Standar Deviasi dibagi Rata-rata. Angka ini menjadi standar ukur kestabilan grafik penjualan.
            $coefficentOfVariation = $average > 0 ? ($stdDev / $average) : 0;

            // Mengurutkan data untuk mencari bulan dengan volume penjualan tertinggi dan terendah
            $sortedMonthly = $monthlyData->sortByDesc('total');
            $highestMonth = Carbon::parse($sortedMonthly->first()->bulan . '-01')->translatedFormat('F Y');
            $lowestMonth = Carbon::parse($sortedMonthly->last()->bulan . '-01')->translatedFormat('F Y');

            // ATURAN SINKRONISASI REKOMENDASI DAN PENYEBAB:
            // Jika angka naik-turunnya di atas 30%, maka dianggap tidak stabil dan diberi ulasan evaluasi kuota.
            if ($coefficentOfVariation > 0.30) {
                $statusPenting = 'PERLU PERHATIAN KHUSUS';
                $alasanAnalisis = 'Kesenjangan penjualan antarbulan sangat tinggi. Distribusi kuota wajib disesuaikan secara dinamis.';
            } else if ($coefficentOfVariation > 0.15) {
                $statusPenting = 'Pantauan Berkala';
                $alasanAnalisis = 'Penjualan mengalami fluktuasi tingkat sedang. Diperlukan monitoring per kuartal.';
            } else {
                $statusPenting = 'Stabil (Aman)';
                $alasanAnalisis = 'Pola permintaan pasar konstan. Alokasi kuota tetap dapat dipertahankan.';
            }

            // Memasukkan hasil olahan ke dalam baris tabel Excel
            $summaryData->push([
                $index + 1,
                $pangkalan->name,
                (int)round($average) . ' Tabung',
                $highestMonth,
                $lowestMonth,
                round($coefficentOfVariation * 100, 1) . '%', // Mengubah angka desimal menjadi format persen
                $statusPenting,
                $alasanAnalisis
            ]);
        }

        // CARA MENGURUTKAN PRIORITAS:
        // Pangkalan dengan status 'PERLU PERHATIAN KHUSUS' dipaksa otomatis naik ke urutan baris paling atas
        return $summaryData->sortBy(function($row) {
            return $row[6] === 'PERLU PERHATIAN KHUSUS' ? 0 : 1;
        });
    }

    /**
     * Mengatur baris judul (Header) tabel di sheet pertama.
     */
    public function headings(): array
    {
        return [
            ['DASHBOARD UTAMA MONITORING AGEN: MATRIKS EVALUASI DISTRIBUSI'],
            ['Diunduh tgl:', Carbon::now()->translatedFormat('d F Y H:i') . ' WIB'],
            ['Berikut adalah daftar pangkalan yang diurutkan berdasarkan prioritas pengawasan volume jual.'],
            [''],
            ['No', 'Nama Pangkalan', 'Rata-rata / Bulan', 'Bulan Tertinggi', 'Bulan Terendah', 'Tingkat Fluktuasi (CV)', 'Rekomendasi Tindakan', 'Penyebab / Alasan Analisis']
        ];
    }

    /**
     * Mengatur desain pewarnaan teks dan latar belakang header tabel.
     */
    public function styles(Worksheet $sheet): array
    {
        return [
            1 => ['font' => ['bold' => true, 'size' => 14, 'color' => ['rgb' => '111111']]],
            2 => ['font' => ['italic' => true, 'size' => 10]],
            5 => [
                'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
                'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => '1F4E79']]
            ]
        ];
    }

    /**
     * Mengatur tata letak dan pewarnaan otomatis (Conditional Formatting) sel setelah sheet selesai dibuat.
     */
    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function (AfterSheet $event) {
                $sheet = $event->sheet->getDelegate();
                $highestRow = $sheet->getHighestRow();

                // Menggabungkan kolom untuk area baris judul atas
                $sheet->mergeCells("A1:H1");
                $sheet->mergeCells("A2:H2");
                $sheet->mergeCells("A3:H3");

                // Memberikan garis pembatas (Border) tipis abu-abu ke seluruh sel tabel
                $styleArray = [
                    'borders' => [
                        'allBorders' => [
                            'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                            'color' => ['rgb' => 'CCCCCC'],
                        ],
                    ],
                ];
                $sheet->getStyle("A5:H{$highestRow}")->applyFromArray($styleArray);

                // ATURAN WARNA OTOMATIS: 
                // Membaca isi kolom G, jika status kritis maka otomatis diwarnai merah muda cerah.
                for ($row = 6; $row <= $highestRow; $row++) {
                    $cellValue = $sheet->getCell("G{$row}")->getValue();
                    if (str_contains($cellValue, 'PERHATIAN KHUSUS')) {
                        $sheet->getStyle("G{$row}")->getFont()->setBold(true)->getColor()->setRGB('9C0006');
                        $sheet->getStyle("G{$row}")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('FFC7CE');
                    } elseif (str_contains($cellValue, 'Pantauan Berkala')) {
                        $sheet->getStyle("G{$row}")->getFont()->setBold(true)->getColor()->setRGB('9C6500');
                        $sheet->getStyle("G{$row}")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('FFEB9C');
                    } else {
                        $sheet->getStyle("G{$row}")->getFont()->getColor()->setRGB('006100');
                        $sheet->getStyle("G{$row}")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('C6EFCE');
                    }
                }
            }
        ];
    }
}

class PangkalanSalesSheet implements FromCollection, WithTitle, WithHeadings, WithStyles, ShouldAutoSize, WithEvents
{
    private User $pangkalan;
    private string $highestMonth = '-';
    private string $lowestMonth = '-';
    private Collection $monthlySummary;

    public function __construct(User $pangkalan)
    {
        $this->pangkalan = $pangkalan;
        $this->monthlySummary = collect();
    }

    /**
     * Mengatur nama sheet pangkalan (dibersihkan dari karakter spesial agar tidak error).
     */
    public function title(): string
    {
        return substr(preg_replace('/[^A-Za-z0-9 ]/', '', $this->pangkalan->name), 0, 30);
    }

    /**
     * Mengambil data transaksi harian riil pangkalan untuk dicetak ke dalam sheet detail.
     */
    public function collection(): Collection
    {
        Carbon::setLocale('id');
        
        // Mengambil data urut dari tanggal terlama ke terbaru dan membuang data duplikat tanggal
        $data = DataPenjualan::where(['user_id' => $this->pangkalan->id])
            ->select('tanggal', 'jumlah')
            ->orderBy('tanggal', 'asc')
            ->get()
            ->unique('tanggal');

        // Mengambil data rekap bulanan untuk bahan tabel ringkasan di bagian bawah
        $analytics = DataPenjualan::where(['user_id' => $this->pangkalan->id])
            ->select(
                DB::raw("DATE_FORMAT(tanggal, '%Y-%m') as bulan_tahun"),
                DB::raw("SUM(jumlah) as total")
            )
            ->groupBy('bulan_tahun')
            ->orderBy('total', 'desc')
            ->get();

        if ($analytics->isNotEmpty()) {
            $this->highestMonth = Carbon::parse($analytics->first()->bulan_tahun . '-01')->translatedFormat('F Y');
            $this->lowestMonth = Carbon::parse($analytics->last()->bulan_tahun . '-01')->translatedFormat('F Y');
            
            $this->monthlySummary = $analytics->map(function ($item) {
                return [
                    'bulan' => Carbon::parse($item->bulan_tahun . '-01')->translatedFormat('F Y'),
                    'total' => (int)$item->total
                ];
            });
        }

        // Aturan proteksi: Jika data kosong, otomatis cetak angka 0 agar tidak kosong/NaN
        if ($data->isEmpty()) {
            return collect([[Carbon::today()->format('Y-m-d'), 0]]);
        }

        return $data->map(function ($item) {
            return [
                Carbon::parse($item->tanggal)->translatedFormat('d F Y'),
                $item->jumlah !== null && $item->jumlah !== '' ? (int)$item->jumlah : 0 // Proteksi angka 0 mutlak
            ];
        });
    }

    /**
     * Mengatur bagian informasi tata letak atas berkas rekapitulasi pangkalan.
     */
    public function headings(): array
    {
        return [
            ['LAPORAN REKAPITULASI PENJUALAN LPG OLEH AGEN'],
            ['Nama Pangkalan:', $this->pangkalan->name],
            ['Alamat Lokasi:', $this->pangkalan->alamat ?? 'Jember'],
            [""],
            ['Tanggal Transaksi', 'Volume Penjualan (Tabung)']
        ];
    }

    /**
     * Desain pewarnaan tabel transaksi harian pangkalan (Hijau).
     */
    public function styles(Worksheet $sheet): array
    {
        return [
            1 => ['font' => ['bold' => true, 'size' => 14, 'color' => ['rgb' => '111111']]],
            2 => ['font' => ['bold' => true]],
            3 => ['font' => ['bold' => true]],
            5 => [
                'font' => ['bold' => true, 'color' => ['rgb' => 'FFFFFF']],
                'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID, 'startColor' => ['rgb' => '7BB31A']]
            ]
        ];
    }

    /**
     * Menyusun tabel ringkasan bulanan dan kotak ulasan Agen di bagian bawah setelah data harian dicetak.
     */
    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function (AfterSheet $event) {
                $sheet = $event->sheet->getDelegate();
                $highestRow = $sheet->getHighestRow();
                
                $sheet->mergeCells("A1:B1");
                
                $styleArray = [
                    'borders' => [
                        'allBorders' => [
                            'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                            'color' => ['rgb' => 'CCCCCC'],
                        ],
                    ],
                ];
                $sheet->getStyle("A5:B{$highestRow}")->applyFromArray($styleArray);
                $sheet->getStyle("B6:B{$highestRow}")->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT);

                // 1. MEMBUAT TABEL REKAP BULANAN (Warna Biru)
                $summaryStartRow = $highestRow + 3;
                $sheet->mergeCells("A{$summaryStartRow}:B{$summaryStartRow}");
                $sheet->setCellValue("A{$summaryStartRow}", " RINGKASAN TOTAL PENJUALAN PER BULAN (TERTINGGI KE TERENDAH)");
                $sheet->getStyle("A{$summaryStartRow}")->getFont()->setBold(true)->setColor(new \PhpOffice\PhpSpreadsheet\Style\Color(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE));
                $sheet->getStyle("A{$summaryStartRow}")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('4E73DF');

                $headerRow = $summaryStartRow + 1;
                $sheet->setCellValue("A{$headerRow}", "Bulan & Tahun");
                $sheet->setCellValue("B{$headerRow}", "Total Terjual (Tabung)");
                $sheet->getStyle("A{$headerRow}:B{$headerRow}")->getFont()->setBold(true);
                $sheet->getStyle("A{$headerRow}:B{$headerRow}")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('EAECF4');

                // Menuliskan isi rekap bulanan yang sudah berurutan dari tertinggi
                $currentRow = $headerRow + 1;
                foreach ($this->monthlySummary as $sum) {
                    $sheet->setCellValue("A{$currentRow}", $sum['bulan']);
                    $sheet->setCellValue("B{$currentRow}", $sum['total']);
                    $sheet->getStyle("B{$currentRow}")->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_RIGHT);
                    $currentRow++;
                }
                $sheet->getStyle("A{$headerRow}:B" . ($currentRow - 1))->applyFromArray($styleArray);

                // 2. MEMBUAT KOTAK KESIMPULAN MONITORING (Warna Merah)
                $analysisStartRow = $currentRow + 2;
                $sheet->mergeCells("A{$analysisStartRow}:B{$analysisStartRow}");
                $sheet->setCellValue("A{$analysisStartRow}", " KESIMPULAN ANALISIS & MONITORING AGEN");
                $sheet->getStyle("A{$analysisStartRow}")->getFont()->setBold(true)->setColor(new \PhpOffice\PhpSpreadsheet\Style\Color(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE));
                $sheet->getStyle("A{$analysisStartRow}")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setRGB('E74A3B');

                $r1 = $analysisStartRow + 1; 
                $sheet->mergeCells("A{$r1}:B{$r1}");
                $sheet->setCellValue("A{$r1}", " • Penjualan volume tertinggi pangkalan ini tercatat pada periode: " . $this->highestMonth);
                
                $r2 = $analysisStartRow + 2; 
                $sheet->mergeCells("A{$r2}:B{$r2}");
                $sheet->setCellValue("A{$r2}", " • Penjualan volume terendah pangkalan ini tercatat pada periode: " . $this->lowestMonth);
                
                $r3 = $analysisStartRow + 3; 
                $sheet->mergeCells("A{$r3}:B{$r3}");
                $sheet->setCellValue("A{$r3}", " • CATATAN AGEN: Jadikan bulan-bulan dengan volume terendah sebagai acuan untuk menyesuaikan kuota distribusi secara efisien, guna menghindari penumpukan stok berlebih di pangkalan.");

                // Membuat garis bingkai tebal warna merah mengelilingi teks kesimpulan
                $boxRange = "A{$analysisStartRow}:B" . ($analysisStartRow + 4);
                $sheet->getStyle($boxRange)->getBorders()->getOutline()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_MEDIUM)->getColor()->setRGB('E74A3B');
            },
        ];
    }
}