<?php

namespace Modules\Lpj\Imports;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;
use Modules\Lpj\Models\Bucok;
use Carbon\Carbon;
use Exception;

  /**
 * Kelas untuk mengimpor data Excel ke tabel bucoks
 * Menggunakan Laravel Excel dengan validasi dan batch processing
 * Data dimulai dari baris ke-5 tanpa header
 */
class BucokImport implements ToCollection, WithStartRow, WithValidation, WithBatchInserts, WithChunkReading
{
    private $importedCount = 0;
    private $skippedCount  = 0;
    private $createdCount  = 0;
    private $updatedCount  = 0;
    private $errors        = [];

      /**
     * Menentukan baris mulai membaca data (baris ke-5)
     *
     * @return int
     */
    public function startRow(): int
    {
        return 5;
    }

      /**
     * Memproses koleksi data dari Excel
     *
     * @param Collection $collection
     * @return void
     */
    public function collection(Collection $collection)
    {
        DB::beginTransaction();

        try {
            foreach ($collection as $rowIndex => $row) {
                  // Log setiap baris yang diproses
                Log::info('Processing Bucok import row', [
                    'row_number' => $rowIndex + 5,   // +5 karena mulai dari baris 5
                    'row_data'   => $row->toArray()
                ]);

                  // Konversi row ke array dengan indeks numerik
                $rowArray = $row->toArray();

                  // Skip baris kosong
                if (empty(array_filter($rowArray))) {
                    continue;
                }

                  // Validasi data baris
                $mappedData = $this->mapRowToBucok($rowArray, $rowIndex + 5);

                  // Update atau create berdasarkan nomor_tiket
                if (!empty($mappedData['nomor_tiket'])) {
                      // Update atau create berdasarkan nomor_tiket
                    $bucok = Bucok::updateOrCreate(
                        ['nomor_tiket' => $mappedData['nomor_tiket']],            // Kondisi pencarian
                        array_merge($mappedData, ['updated_by' => auth()->id()])  // Data yang akan diupdate/create
                    );

                      // Log dan tracking apakah data di-update atau di-create
                    if ($bucok->wasRecentlyCreated) {
                        $this->createdCount++;
                        Log::info('Bucok created successfully', [
                            'row_number'  => $rowIndex + 5,
                            'nomor_tiket' => $mappedData['nomor_tiket'],
                            'action'      => 'created'
                        ]);
                    } else {
                        $this->updatedCount++;
                        Log::info('Bucok updated successfully', [
                            'row_number'  => $rowIndex + 5,
                            'nomor_tiket' => $mappedData['nomor_tiket'],
                            'action'      => 'updated'
                        ]);
                    }
                }

                $this->importedCount++;
            }

            DB::commit();

              // Log summary
            Log::info('Bucok import completed', [
                'imported'     => $this->importedCount,
                'skipped'      => $this->skippedCount,
                'total_errors' => count($this->errors)
            ]);

        } catch (Exception $e) {
            DB::rollback();
            Log::error('Bucok import failed', ['error' => $e->getMessage()]);
            throw $e;
        }
    }

      /**
     * Mapping data Excel berdasarkan indeks kolom ke struktur model Bucok
     * Kolom dimulai dari indeks 0 (A=0, B=1, C=2, dst.)
     *
     * @param array $row
     * @param int $rowNumber
     * @return array
     */
    private function mapRowToBucok(array $row, int $rowNumber): array
    {
        return [
            'no'                     => $row[0] ?? null,                                        // Kolom A
            'tanggal'                => !empty($row[1]) ? $this->parseDate($row[1]) : null,     // Kolom B
            'bulan'                  => $row[2] ?? null,                                        // Kolom C
            'tahun'                  => $row[3] ?? null,                                        // Kolom D
            'tanggal_penuh'          => !empty($row[4]) ? $this->parseDate($row[4]) : null,     // Kolom E
            'nomor_categ'            => $row[5] ?? null,                                        // Kolom F
            'coa_summary'            => $row[6] ?? null,                                        // Kolom G
            'nomor_coa'              => $row[7] ?? null,                                        // Kolom H
            'nama_coa'               => $row[8] ?? null,                                        // Kolom I
            'nomor_tiket'            => $row[9] ?? null,                                        // Kolom J - Auto-generate jika kosong
            'deskripsi'              => $row[10] ?? null,                                       // Kolom K
            'nominal'                => $this->parseNumeric($row[11] ?? 0),                     // Kolom L
            'penyelesaian'           => $row[12] ?? 'Belum Selesai',                            // Kolom M
            'umur_aging'             => $this->parseNumeric($row[13] ?? 0),                     // Kolom N
            'cost_center'            => $row[14] ?? null,                                       // Kolom O
            'nama_sub_direktorat'    => $row[15] ?? null,                                       // Kolom P
            'nama_direktorat_cabang' => $row[16] ?? null,                                       // Kolom Q
            'tanggal_penyelesaian'   => !empty($row[17]) ? $this->parseDate($row[17]) : null,   // Kolom R
            'nominal_penyelesaian'   => $this->parseNumeric($row[18] ?? 0),                     // Kolom S
            'nominal_berjalan'       => $this->parseNumeric($row[19] ?? 0),                     // Kolom T
            'amortisasi_berjalan'    => $this->parseNumeric($row[20] ?? 0),                     // Kolom U
            'sistem_berjalan'        => $this->parseNumeric($row[21] ?? 0),                     // Kolom V
            'lainnya_berjalan'       => $this->parseNumeric($row[22] ?? 0),                     // Kolom W
            'nominal_gantung'        => $this->parseNumeric($row[23] ?? 0),                     // Kolom X
            'aset_gantung'           => $this->parseNumeric($row[24] ?? 0),                     // Kolom Y
            'keterangan_gantung'     => $row[25] ?? null,                                       // Kolom Z
            'lainnya_satu'           => $row[26] ?? null,                                       // Kolom AA
            'lainnya_dua'            => $row[27] ?? null,                                       // Kolom AB
            'created_by'             => auth()->id(),
            'updated_by'             => auth()->id()
        ];
    }

      /**
     * Parse tanggal dari berbagai format
     *
     * @param mixed $dateValue
     * @return Carbon|null
     */
    private function parseDate($dateValue)
    {
        if (empty($dateValue)) {
            return null;
        }

        try {
              // Jika berupa angka Excel date serial
            if (is_numeric($dateValue)) {
                return Carbon::createFromFormat('Y-m-d', \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue)->format('Y-m-d'));
            }

              // Jika berupa string tanggal
            return Carbon::parse($dateValue);
        } catch (Exception $e) {
            Log::warning('Failed to parse date', ['value' => $dateValue, 'error' => $e->getMessage()]);
            return null;
        }
    }

      /**
     * Parse nilai numerik dari berbagai format
     *
     * @param mixed $numericValue
     * @return float
     */
    private function parseNumeric($numericValue): float
    {
        if (empty($numericValue)) {
            return 0;
        }

          // Hapus karakter non-numerik kecuali titik dan koma
        $cleaned = preg_replace('/[^0-9.,\-]/', '', $numericValue);

          // Ganti koma dengan titik untuk decimal
        $cleaned = str_replace(',', '.', $cleaned);

        return (float) $cleaned;
    }

      /**
     * Validasi data yang sudah dimapping
     *
     * @param array $data
     * @return \Illuminate\Validation\Validator
     */
    private function validateMappedData(array $data)
    {
        return Validator::make($data, [
            'no'                     => 'nullable|integer',
            'tanggal'                => 'nullable|date',
            'bulan'                  => 'nullable|integer|between:1,12',
            'tahun'                  => 'nullable|integer|min:2000|max:2099',
            'tanggal_penuh'          => 'nullable|date',
            'nomor_categ'            => 'nullable|string|max:50',
            'coa_summary'            => 'nullable|string|max:255',
            'nomor_coa'              => 'nullable|string|max:50',
            'nama_coa'               => 'nullable|string|max:255',
            'nomor_tiket'            => 'nullable|string|max:50',
            'deskripsi'              => 'nullable|string',
            'nominal'                => 'nullable|numeric|min:0',
            'penyelesaian'           => 'nullable|in:Selesai,Belum Selesai,Dalam Proses',
            'umur_aging'             => 'nullable|integer|min:0',
            'cost_center'            => 'nullable|string|max:100',
            'nama_sub_direktorat'    => 'nullable|string|max:255',
            'nama_direktorat_cabang' => 'nullable|string|max:255',
            'tanggal_penyelesaian'   => 'nullable|date',
            'nominal_penyelesaian'   => 'nullable|numeric|min:0',
            'nominal_berjalan'       => 'nullable|numeric|min:0',
            'amortisasi_berjalan'    => 'nullable|numeric|min:0',
            'sistem_berjalan'        => 'nullable|numeric|min:0',
            'lainnya_berjalan'       => 'nullable|numeric|min:0',
            'nominal_gantung'        => 'nullable|numeric|min:0',
            'aset_gantung'           => 'nullable|numeric|min:0',
            'keterangan_gantung'     => 'nullable|string',
            'lainnya_satu'           => 'nullable|string',
            'lainnya_dua'            => 'nullable|string'
        ]);
    }

      /**
     * Aturan validasi untuk seluruh file Excel (tidak digunakan karena tanpa header)
     *
     * @return array
     */
    public function rules(): array
    {
        return [];
    }

      /**
     * Ukuran batch untuk insert
     *
     * @return int
     */
    public function batchSize(): int
    {
        return 100;
    }

      /**
     * Ukuran chunk untuk membaca file
     *
     * @return int
     */
    public function chunkSize(): int
    {
        return 100;
    }

      /**
     * Mendapatkan jumlah data yang berhasil diimpor
     *
     * @return int
     */
    public function getImportedCount(): int
    {
        return $this->importedCount;
    }

      /**
     * Mendapatkan jumlah data yang berhasil dibuat
     *
     * @return int
     */
    public function getCreatedCount(): int
    {
        return $this->createdCount;
    }

      /**
     * Mendapatkan jumlah data yang berhasil diupdate
     *
     * @return int
     */
    public function getUpdatedCount(): int
    {
        return $this->updatedCount;
    }

      /**
     * Mendapatkan statistik lengkap import
     *
     * @return array
     */
    public function getImportStatistics(): array
    {
        return [
            'total_processed' => $this->importedCount,
            'created'         => $this->createdCount,
            'updated'         => $this->updatedCount,
            'skipped'         => $this->skippedCount,
            'errors'          => count($this->errors)
        ];
    }

      /**
     * Mendapatkan jumlah data yang dilewati
     *
     * @return int
     */
    public function getSkippedCount(): int
    {
        return $this->skippedCount;
    }

      /**
     * Mendapatkan daftar error yang terjadi
     *
     * @return array
     */
    public function getErrors(): array
    {
        return $this->errors;
    }
}
