<?php

namespace Modules\Lpj\Http\Controllers;

use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Facades\Excel;
use Modules\Lpj\Exports\SlikExport;
use Modules\Lpj\Imports\SlikImport;
use Modules\Lpj\Models\Slik;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * Controller untuk mengelola data Slik
 *
 * Menangani operasi CRUD dan import data Slik dari file Excel
 * dengan fitur server-side processing untuk datatables
 *
 * @package Modules\Lpj\Http\Controllers
 */
class SlikController extends Controller
{
    public $user;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->user = Auth::user();
    }

    /**
     * Menampilkan halaman index slik
     *
     * @return \Illuminate\View\View
     */
    public function index()
    {
        return view('lpj::slik.index');
    }

    /**
     * Menampilkan detail slik
     *
     * @param int $id
     * @return \Illuminate\View\View
     */
    public function show($id)
    {
        $slik = Slik::findOrFail($id);
        return view('lpj::slik.show', compact('slik'));
    }

    /**
     * Data untuk datatables dengan server-side processing
     *
     * @param Request $request
     * @return \Illuminate\Http\JsonResponse
     */
    public function dataForDatatables(Request $request)
    {
        // Authorization check dapat ditambahkan sesuai kebutuhan
        // if (is_null($this->user)) {
        //     abort(403, 'Unauthorized access.');
        // }

        // Retrieve data from the database
        $query = Slik::query();

        // Apply search filter if provided
        if ($request->has('search') && !empty($request->get('search'))) {
            $search = $request->get('search');
            $query->where(function ($q) use ($search) {
                $q->where('sandi_bank', 'LIKE', "%$search%")
                  ->orWhere('no_rekening', 'LIKE', "%$search%")
                  ->orWhere('cif', 'LIKE', "%$search%")
                  ->orWhere('nama_debitur', 'LIKE', "%$search%")
                  ->orWhere('nama_cabang', 'LIKE', "%$search%")
                  ->orWhere('jenis_agunan', 'LIKE', "%$search%")
                  ->orWhere('nama_pemilik_agunan', 'LIKE', "%$search%")
                  ->orWhere('alamat_agunan', 'LIKE', "%$search%")
                  ->orWhere('lokasi_agunan', 'LIKE', "%$search%");
            });
        }

        // Apply year filter
        if ($request->has('year') && !empty($request->get('year'))) {
            $query->byYear($request->get('year'));
        }

        // Apply month filter
        if ($request->has('month') && !empty($request->get('month'))) {
            $query->byMonth($request->get('month'));
        }

        // Apply sandi bank filter
        if ($request->has('sandi_bank') && !empty($request->get('sandi_bank'))) {
            $query->where('sandi_bank', $request->get('sandi_bank'));
        }

        // Apply kolektibilitas filter
        if ($request->has('kolektibilitas') && !empty($request->get('kolektibilitas'))) {
            $query->where('kolektibilitas', $request->get('kolektibilitas'));
        }

        // Apply jenis agunan filter
        if ($request->has('jenis_agunan') && !empty($request->get('jenis_agunan'))) {
            $query->where('jenis_agunan', $request->get('jenis_agunan'));
        }

        // Apply sorting if provided
        if ($request->has('sortOrder') && !empty($request->get('sortOrder'))) {
            $order  = $request->get('sortOrder');
            $column = $request->get('sortField', 'created_at');
            $query->orderBy($column, $order);
        } else {
            $query->orderBy('created_at', 'desc');
        }

        // Get the total count of records
        $totalRecords = $query->count();

        // Apply pagination if provided
        if ($request->has('page') && $request->has('size')) {
            $page   = $request->get('page');
            $size   = $request->get('size');
            $offset = ($page - 1) * $size;    // Calculate the offset

            $query->skip($offset)->take($size);
        }

        // Get the filtered count of records
        $filteredRecords = $query->count();

        // Get the data for the current page with relationships
        $data = $query->get();

        // Transform data untuk datatables
        $transformedData = $data->map(function ($item) {
            return [
                'id'                     => $item->id,
                'sandi_bank'             => $item->sandi_bank,
                'tahun'                  => $item->tahun,
                'bulan'                  => $item->bulan,
                'no_rekening'            => $item->no_rekening,
                'cif'                    => $item->cif,
                'nama_debitur'           => $item->nama_debitur,
                'kolektibilitas'         => $item->kolektibilitas,
                'kolektibilitas_badge'   => $item->kolektibilitas_badge,
                'fasilitas'              => $item->fasilitas,
                'jenis_agunan'           => $item->jenis_agunan,
                'nama_pemilik_agunan'    => $item->nama_pemilik_agunan,
                'nilai_agunan'           => $item->nilai_agunan_formatted,
                'nilai_agunan_ljk'       => $item->nilai_agunan_ljk_formatted,
                'alamat_agunan'          => $item->alamat_agunan,
                'lokasi_agunan'          => $item->lokasi_agunan,
                'nama_cabang'            => $item->nama_cabang,
                'kode_cabang'            => $item->kode_cabang,
                'created_by'             => $item->creator?->name ?? '-',
                'created_at'             => dateFormat($item->created_at, true)
            ];
        });

        // Calculate the page count
        $pageCount = ceil($totalRecords / ($request->get('size', 10)));

        // Calculate the current page number
        $currentPage = $request->get('page', 1);

        // Return the response data as a JSON object
        return response()->json([
            'draw'            => $request->get('draw'),
            'recordsTotal'    => $totalRecords,
            'recordsFiltered' => $filteredRecords,
            'pageCount'       => $pageCount,
            'page'            => $currentPage,
            'totalCount'      => $totalRecords,
            'data'            => $transformedData,
        ]);
    }

    /**
     * Import data slik dari Excel dengan optimasi memory dan progress tracking
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function import(Request $request)
    {
        Log::info('SlikController: Starting import process with optimizations', [
            'user_id' => Auth::id(),
            'request_size' => $request->header('Content-Length'),
            'has_file' => $request->hasFile('file'),
            'memory_limit' => ini_get('memory_limit'),
            'max_execution_time' => ini_get('max_execution_time')
        ]);

        // Validasi file upload dengan logging detail dan error handling komprehensif
        try {
            // Cek apakah ada file yang diupload
            if (!$request->hasFile('file')) {
                Log::error('SlikController: Tidak ada file yang diupload', [
                    'user_id' => Auth::id(),
                    'files_count' => count($request->allFiles()),
                    'request_data' => $request->all()
                ]);
                throw ValidationException::withMessages(['file' => 'Tidak ada file yang diupload.']);
            }

            $file = $request->file('file');

            // Cek apakah file valid
            if (!$file->isValid()) {
                $error = $file->getError();
                $errorMessage = match($error) {
                    UPLOAD_ERR_INI_SIZE => 'File terlalu besar (melebihi upload_max_filesize).',
                    UPLOAD_ERR_FORM_SIZE => 'File terlalu besar (melebihi MAX_FILE_SIZE).',
                    UPLOAD_ERR_PARTIAL => 'File hanya terupload sebagian.',
                    UPLOAD_ERR_NO_FILE => 'Tidak ada file yang diupload.',
                    UPLOAD_ERR_NO_TMP_DIR => 'Direktori temp tidak tersedia.',
                    UPLOAD_ERR_CANT_WRITE => 'Gagal menulis file ke disk.',
                    UPLOAD_ERR_EXTENSION => 'Upload dibatalkan oleh ekstensi PHP.',
                    default => 'Error upload tidak diketahui: ' . $error
                };

                Log::error('SlikController: File upload tidak valid', [
                    'error' => $error,
                    'error_message' => $errorMessage,
                    'user_id' => Auth::id(),
                    'file_info' => [
                        'name' => $file->getClientOriginalName(),
                        'size' => $file->getSize(),
                        'mime' => $file->getMimeType()
                    ]
                ]);
                throw ValidationException::withMessages(['file' => $errorMessage]);
            }

            $maxFileSize = config('import.slik.max_file_size', 50) * 1024; // dalam KB
            $request->validate([
                'file' => 'required|file|mimes:xlsx,xls|max:' . $maxFileSize
            ]);
            Log::info('SlikController: Validasi file berhasil');
        } catch (\Illuminate\Validation\ValidationException $e) {
            Log::error('SlikController: Validasi file gagal', [
                'errors' => $e->errors(),
                'user_id' => Auth::id(),
                'request_size' => $request->header('Content-Length')
            ]);
            throw $e;
        }

        try {
            $uploadedFile = $request->file('file');
            $originalName = $uploadedFile->getClientOriginalName();
            $fileSize = $uploadedFile->getSize();

            Log::info('SlikController: Memulai import data Slik', [
                'user_id' => Auth::id(),
                'filename' => $originalName,
                'filesize' => $fileSize,
                'filesize_mb' => round($fileSize / 1024 / 1024, 2),
                'mime_type' => $uploadedFile->getMimeType(),
                'extension' => $uploadedFile->getClientOriginalExtension()
            ]);

            // Generate unique import ID
            $importId = uniqid('slik_import_');
            $userId = Auth::id() ?? 1;

            // Cek apakah menggunakan queue processing untuk file besar
            $useQueue = config('import.slik.queue.enabled', false) && $fileSize > (5 * 1024 * 1024); // > 5MB

            // Pastikan direktori temp ada
            $tempDir = storage_path('app/temp');
            if (!file_exists($tempDir)) {
                mkdir($tempDir, 0755, true);
                Log::info('SlikController: Direktori temp dibuat', ['path' => $tempDir]);
            }

            // Simpan file sementara dengan nama unik
            $tempFileName = 'slik_import_' . time() . '_' . uniqid() . '.' . $uploadedFile->getClientOriginalExtension();
            $tempFilePath = $tempDir . '/' . $tempFileName;

            Log::info('SlikController: Memindahkan file ke temp', [
                'temp_path' => $tempFilePath,
                'use_queue' => $useQueue
            ]);

            // Pindahkan file ke direktori temp
            $uploadedFile->move($tempDir, $tempFilePath);

            // Verifikasi file berhasil dipindahkan
            if (!file_exists($tempFilePath)) {
                throw new Exception('File gagal dipindahkan ke direktori temp');
            }

            Log::info('SlikController: File berhasil dipindahkan', [
                'file_size' => filesize($tempFilePath)
            ]);

            if ($useQueue) {
                Log::info('SlikController: Menggunakan queue processing untuk file besar', [
                    'import_id' => $importId,
                    'file_size_mb' => round($fileSize / 1024 / 1024, 2)
                ]);

                // Dispatch job ke queue
                \Modules\Lpj\Jobs\ProcessSlikImport::dispatch($tempFilePath, $userId, $importId);

                return redirect()->back()->with('success', 'Import sedang diproses di background. ID: ' . $importId);
            }

            // Import langsung untuk file kecil
            Log::info('SlikController: Processing file directly', [
                'import_id' => $importId,
                'file_size_mb' => round($fileSize / 1024 / 1024, 2)
            ]);

            // Set optimasi memory untuk import langsung
            $memoryLimit = config('import.slik.memory_limit', 256);
            ini_set('memory_limit', $memoryLimit . 'M');
            ini_set('max_execution_time', config('import.slik.timeout', 30000));

            // Enable garbage collection jika diizinkan
            if (config('import.slik.enable_gc', true)) {
                gc_enable();
            }

            // Proses import menggunakan SlikImport class
            Log::info('SlikController: Memulai proses Excel import');
            $import = new SlikImport();
            Excel::import($import, $tempFilePath);
            Log::info('SlikController: Excel import selesai');

            // Force garbage collection setelah selesai
            if (config('import.slik.enable_gc', true)) {
                gc_collect_cycles();
            }

            // Hapus file temporary setelah import
            if (file_exists($tempFilePath)) {
                unlink($tempFilePath);
                Log::info('SlikController: File temp berhasil dihapus');
            }

            Log::info('SlikController: Data Slik berhasil diimport', [
                'user_id' => Auth::id(),
                'import_id' => $importId
            ]);

            return redirect()->back()->with('success', 'Data Slik berhasil diimport dari file Excel.');

        } catch (Exception $e) {
            // Hapus file temporary jika ada error
            if (isset($tempFilePath) && file_exists($tempFilePath)) {
                unlink($tempFilePath);
                Log::info('SlikController: File temp dihapus karena error');
            }

            Log::error('SlikController: Gagal import data Slik', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'memory_usage' => memory_get_usage(true)
            ]);

            return redirect()->back()->with('error', 'Gagal import data Slik: ' . $e->getMessage());
        }
    }

    /**
     * Menampilkan halaman form import
     *
     * @return \Illuminate\View\View
     */
    public function importForm()
    {
        return view('lpj::slik.import');
    }

    /**
     * Download template Excel untuk import
     *
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function downloadTemplate()
    {
        $templatePath = resource_path('metronic/slik.xlsx');

        if (!file_exists($templatePath)) {
            return redirect()->back()->with('error', 'Template file tidak ditemukan.');
        }

        return response()->download($templatePath, 'template_slik.xlsx');
    }

    /**
     * Get import progress
     *
     * @param string $importId
     * @return \Illuminate\Http\JsonResponse
     */
    public function progress(string $importId)
    {
        try {
            $progressService = new \Modules\Lpj\Services\ImportProgressService();
            $progress = $progressService->getProgress($importId);

            if (!$progress) {
                return response()->json([
                    'success' => false,
                    'message' => 'Progress import tidak ditemukan'
                ], 404);
            }

            return response()->json([
                'success' => true,
                'progress' => $progress
            ]);

        } catch (\Exception $e) {
            Log::error('SlikController: Error getting progress', [
                'import_id' => $importId,
                'error' => $e->getMessage()
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Gagal mendapatkan progress: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Export data SLIK ke Excel
     * 
     * Method ini menangani export data SLIK ke format Excel dengan:
     * - Logging aktivitas export
     * - Error handling yang proper
     * - Format Excel yang sesuai dengan struktur SLIK
     * 
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
     */
    public function export()
    {
        try {
            Log::info('SLIK Export: Memulai proses export data SLIK', [
                'user_id' => Auth::id(),
                'timestamp' => now(),
                'memory_usage' => memory_get_usage(true) / 1024 / 1024 . ' MB'
            ]);
            
            // Hitung total data yang akan di-export
            $totalData = Slik::count();
            
            Log::info('SLIK Export: Informasi data export', [
                'total_records' => $totalData,
                'user_id' => Auth::id(),
                'timestamp' => now()
            ]);
            
            // Generate nama file dengan timestamp
            $filename = 'slik_export_' . date('Y-m-d_H-i-s') . '.xlsx';
            
            // Proses export menggunakan SlikExport class
            $export = Excel::download(new SlikExport(), $filename);
            
            Log::info('SLIK Export: Berhasil generate file export', [
                'filename' => $filename,
                'total_records' => $totalData,
                'user_id' => Auth::id(),
                'timestamp' => now(),
                'memory_peak' => memory_get_peak_usage(true) / 1024 / 1024 . ' MB'
            ]);
            
            return $export;
            
        } catch (\Exception $e) {
            Log::error('SLIK Export: Gagal melakukan export data SLIK', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id(),
                'timestamp' => now(),
                'memory_usage' => memory_get_usage(true) / 1024 / 1024 . ' MB'
            ]);
            
            return response()->json([
                'success' => false,
                'message' => 'Gagal melakukan export data SLIK: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Truncate all SLIK data
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    public function truncate()
    {
        try {
            DB::beginTransaction();
            
            Log::info('SLIK Truncate: Memulai proses truncate data SLIK', [
                'user_id' => Auth::id(),
                'timestamp' => now()
            ]);
            
            // Truncate tabel SLIK
            Slik::truncate();
            
            DB::commit();
            
            Log::info('SLIK Truncate: Berhasil menghapus semua data SLIK', [
                'user_id' => Auth::id(),
                'timestamp' => now()
            ]);
            
            return response()->json([
                'success' => true,
                'message' => 'Semua data SLIK berhasil dihapus'
            ]);
            
        } catch (\Exception $e) {
            DB::rollback();
            
            Log::error('SLIK Truncate: Gagal menghapus data SLIK', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'user_id' => Auth::id(),
                'timestamp' => now()
            ]);
            
            return response()->json([
                'success' => false,
                'message' => 'Gagal menghapus data SLIK: ' . $e->getMessage()
            ], 500);
        }
    }
}
