<?php

namespace Modules\Lpj\Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Modules\Basicdata\Models\Branch;
use Modules\Lpj\Models\Penilaian;
use Modules\Usermanagement\Models\User;
use Modules\Lpj\Models\PenilaianTeam;
use Modules\Lpj\Models\Permohonan;

class MigPenilaianAndPenilainTeamSeeder extends Seeder
{
    protected $errorLogFile = __DIR__ . '/csv/penilaian/penilaian.team.fix.new_20251012_error.csv';

    /**
     * Run the database seeds.
     */
    public function run()
    {
        // Bersihkan/Inisialisasi file error log
        $this->initializeErrorLog();
        // Path ke file csv
        $filePath = realpath(__DIR__ . '/csv/penilaian/penilaian.team.fix.new_20251012.csv');

        if (!$filePath) {
            Log::error('File csv tidak ditemukan: ' . __DIR__ . '/csv/penilaian/penilaian.team.fix.new_20251012.csv');
            $this->command->error('File csv tidak ditemukan.');
            return;



        }

        if (($handle = fopen($filePath, 'r')) === false) {
            Log::error('Gagal membuka file CSV: ' . $filePath);
            $this->command->error('Gagal membuka file CSV.');
            return;
        }

        $header = fgetcsv($handle, 0, ',');
        $rows = [];
        $batchSize = 500; // Ukuran batch
        $userDataChace = [];
        $nomorRegisCahce = [];
        $errorCount = 0; // Inisialisasi variabel errorCount
        $errorDebitureIds = []; // Inisialisasi array errorDebitureIds
        $totalData = 0;

        // Menghitung total data di file CSV
        while (($data = fgetcsv($handle, 0, ',')) !== false) {
            $totalData++;
        }

        rewind($handle); // Reset pointer ke awal file
        fgetcsv($handle, 0, ','); // Skip header

        $batchCount = 0;
        $currentRow = 0;

        while (($data = fgetcsv($handle, 0, ',')) !== false) {
            if (count($data) != count($header)) {
                Log::warning('Baris CSV memiliki jumlah kolom yang tidak sesuai: ' . json_encode($data));
                continue;
            }

            $rows[] = array_combine($header, $data);
            $currentRow++;

            // Jika sudah mencapai batch size, proses batch
            if (count($rows) >= $batchSize) {
                $batchCount++;
                $this->command->info("Memproses batch ke-{$batchCount} ({$currentRow}/{$totalData})");
                $this->processBatch($rows, $nomorRegisCahce, $userDataChace, $errorCount, $errorDebitureIds, $totalData, $batchCount, $currentRow);
                $rows = [];
            }
        }

        // Proses sisa data jika ada
        // print_r($rows[0]);
        if (!empty($rows)) {
            $batchCount++;
            $this->command->info("Memproses batch ke-{$batchCount} ({$currentRow}/{$totalData})");
            $this->processBatch($rows, $nomorRegisCahce, $userDataChace, $errorCount, $errorDebitureIds, $totalData, $batchCount, $currentRow);
        }

        fclose($handle);

        $this->command->info("Data debiture berhasil dimigrasikan. Total data: {$totalData}, Total batch: {$batchCount}, Total error: {$errorCount}");
    }




    private function processBatch(
        array $rows,
        array &$userDataChace,
        array &$nomorRegisCahce,
        int &$errorCount,
        array &$errorDebitureIds,
        int $totalData,
        int $batchCount,
        int $currentRow
    ) {
        $userData = [];
        foreach ($rows as $index => $row) {
            try {
                // Jalankan setiap baris dengan transaksi sendiri
                //DB::beginTransaction();

                // Cek apakah sudah diproses
                $existingRecord = Penilaian::where('nomor_registrasi', $row['mig_nomor_registrasi'])->first();
                if ($existingRecord && $existingRecord->created_at) {
                    $this->command->info('Data sudah diproses sebelumnya: ' . $row['mig_nomor_registrasi']);
                    //continue;
                }

                // Ambil nomor registrasi
                $nomor_registrasi = $this->getNomorRegistrasiPermohonan($row['mig_nomor_registrasi'], $nomorRegisCahce);
                if (!$nomor_registrasi) {
                    throw new \Exception($row['mig_nomor_registrasi']."Nomor registrasi tidak valid");
                }

                // Ambil user ID
                $userId = $this->getUserId($row['mig_user_id'], $userDataChace);
                if (!$userId) {
                    //   $this->logError($row['mig_user_id'], 'Salah satu user tidak ditemukan');
                    throw new \Exception($row['mig_user_id'] . " User tidak ditemukan");
                    continue;
                }

                $userIdUpdate = $this->getUserIdData($row['mig_created_by'] ?? null, $userData)['id'];
                $userIdOtorisasi = $this->getUserIdData($row['mig_authorized_by'] ?? null, $userData)['id'];

                if (!$userIdUpdate || !$userIdOtorisasi) {
                    // $this->logError($userIdUpdate, 'Salah satu user tidak ditemukan');
                    //continue;
                }

                // Mapping field user
                $mapUser = [
                    'created_by' => $userIdUpdate,
                    'updated_by' => $userIdUpdate,
                    'authorized_by' => $userIdOtorisasi,
                ];

                // Ambil team ID
                $teamId = $this->checkTeams($row['mig_team_id']);
                if (!$teamId) {
                    throw new \Exception("Team tidak ditemukan");
                }

                $idPenilaian = Penilaian::orderBy('id', 'desc')->first()->id;

                $data = [
                    'id' => $idPenilaian+1,
                    'nomor_registrasi' => $nomor_registrasi,
                    'jenis_penilaian_id' => 1,
                    'tanggal_kunjungan' => $this->parseTimestamp($row['mig_tanggal_kunjungan']) ?? now(),
                    'waktu_penilaian' => $this->parseTimestamp($row['mig_waktu_penilaian']),
                    'status' => 'done',
                    'keterangan' => null,
                    'created_at' => $this->parseTimestamp($row['mig_created_at']),
                    'updated_at' => $this->parseTimestamp($row['mig_updated_at']),
                    'authorized_by' => $mapUser['authorized_by'],
                    'created_by' => $mapUser['created_by'],
                    'updated_by' => $mapUser['updated_by']
                ];

                if($nomor_registrasi=='251722'){
                    Log::info("Data penilaian 251722 : ",$data);
                }

                // Buat penilaian
                $penilaian = Penilaian::updateOrCreate([
                    'nomor_registrasi' => $nomor_registrasi
                ],[
                    'id' => $idPenilaian+1,
                    'nomor_registrasi' => $nomor_registrasi,
                    'jenis_penilaian_id' => 1,
                    'tanggal_kunjungan' => $this->parseTimestamp($row['mig_tanggal_kunjungan']) ?? now(),
                    'waktu_penilaian' => $this->parseTimestamp($row['mig_waktu_penilaian']),
                    'status' => 'done',
                    'keterangan' => null,
                    'created_at' => $this->parseTimestamp($row['mig_created_at']),
                    'updated_at' => $this->parseTimestamp($row['mig_updated_at']),
                    'authorized_by' => $mapUser['authorized_by'],
                    'created_by' => $mapUser['created_by'],
                    'updated_by' => $mapUser['updated_by'],
                ]);

                //DB::commit();

                // Buat tim penilaian
                $roles = ['surveyor', 'penilai'];
                foreach ($roles as $role) {
                     $idPenilaianTeam = PenilaianTeam::orderBy('id', 'desc')->first()->id;

                    PenilaianTeam::updateOrCreate([
                        'penilaian_id' => $penilaian->id
                    ],[
                        'id' => $idPenilaianTeam+1,
                        'penilaian_id' => $penilaian->id,
                        'user_id' => $userId,
                        'role' => $role,
                        'team_id' => $teamId,
                        'created_at' => $this->parseTimestamp($row['mig_created_at']),
                        'updated_at' => $this->parseTimestamp($row['mig_updated_at']),
                    ]);
                }

                // Commit transaksi
                //DB::commit();
                $this->command->info('Proses data penilaian ' . $row['mig_nomor_lpj'] . ' (' . ($index + 1) . '/' . count($rows) . ')');

            } catch (\Exception $e) {
                // Rollback jika ada error
                //DB::rollBack();

                Log::error('Error pada baris: ' . json_encode($row) . '. Pesan: ' . $e->getMessage());
                $errorCount++;
                $errorDebitureIds[] = $row['mig_team_id'] ?? '-';
                $this->logError($row['mig_team_id'] ?? '-', $e->getMessage());

                continue;
            }
        }

        $this->command->info("Batch {$batchCount} selesai. Total error: " . count($errorDebitureIds));
    }


    private function getNomorRegistrasiPermohonan($nomor_registrasi_id, $nomorRegisCahce)
    {
        if (isset($nomorRegisCahce[$nomor_registrasi_id])) {
            return $nomorRegisCahce[$nomor_registrasi_id];
        }

        $nomorRegis = Permohonan::where('nomor_registrasi', $nomor_registrasi_id)->first();

        if (!$nomorRegis) {
            return null;
        }

        $nomorRegisCahce[$nomor_registrasi_id] = $nomorRegis->nomor_registrasi;
        return $nomorRegis->nomor_registrasi;
    }
    private function getUserIdData(?string $code, array &$cache): array
    {
        if (!$code) {
            return ['id' => null, 'branch_id' => null];
        }

        if (isset($cache[$code])) {
            return $cache[$code];
        }

        $user = User::where('nik', $code)->first();

        if ($user) {
            $cache[$code] = ['id' => $user->id, 'branch_id' => $user->branch_id];
            return $cache[$code];
        }

        return ['id' => null, 'branch_id' => null];
    }

    private function getUserId($mig_user_id, $userDataChace)
    {
        if (isset($userDataChace[$mig_user_id])) {
            return $userDataChace[$mig_user_id];
        }

        $userId = User::where('nik', $mig_user_id)->first();

        if (!$userId) {
            return null;
        }

        $userDataChace[$mig_user_id] = $userId->id;
        return $userId->id;
    }

    private function checkTeams($code): int
    {
        $mapping = [
            '01' => 1,
            '02' => 2,
            '04' => 4,
            '07' => 5,
            '06' => 3,
        ];
        return $mapping[(string)$code] ?? 1;
    }


    private function parseTimestamp(?string $timestamp): ?string
    {
        try {
            if ($timestamp) {
                // Cek jika format hanya tanggal (Y-m-d)
                if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $timestamp)) {
                    return \Carbon\Carbon::createFromFormat('Y-m-d', $timestamp)
                        ->startOfDay()
                        ->toDateTimeString();
                }
                // Format lengkap (Y-m-d H:i:s)
                if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $timestamp)) {
                    return \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $timestamp)->toDateTimeString();
                }
                // Format d/m/Y H:i:s (contoh: 28/4/2017 14:43:43)
                if (preg_match('/^\d{1,2}\/\d{1,2}\/\d{4} \d{2}:\d{2}:\d{2}$/', $timestamp)) {
                    return \Carbon\Carbon::createFromFormat('d/m/Y H:i:s', $timestamp)->toDateTimeString();
                }
            }
            return null;
        } catch (\Exception $e) {
            Log::error('Gagal memparsing timestamp: ' . $timestamp . '. Pesan: ' . $e->getMessage());
            return null;
        }
    }


    private function initializeErrorLog()
    {
        // Jika file lama ada, hapus
        if (file_exists($this->errorLogFile)) {
            unlink($this->errorLogFile);
        }

        // Buat file baru dengan header
        $handle = fopen($this->errorLogFile, 'w');
        fputcsv($handle, ['mig_kd_debitur_seq', 'Error']);
        fclose($handle);
    }

    private function logError(string $kode, string $message)
    {
        // Catat ke log
        Log::error("Error migrasi debiture [$kode]: $message");

        // Tulis ke file error
        $handle = fopen($this->errorLogFile, 'a');
        fputcsv($handle, [$kode, $message]);
        fclose($handle);
    }

}
