<?php

namespace App\Http\Controllers\Admin;

use App\CampaignsJobProvider;
use App\DaSystemData;
use App\Logging\CloudWatchLoggerFactory;
use App\Http\Controllers\Controller;
use App\Imports\DaSystemDataImport;
use App\Slack;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Support\Facades\DB;

class DaSystemDataController extends Controller
{

    // ─── DA Loan Data ────────────────────────────────────────────────────────

    public static function registry(){
        return [
            [
                'name'    => 'Partners',
                'summary' => 'Manage DA system partner configurations and details.',
                'url'     => null,//'/admin/da-system/partners',
            ],
            [
                'name'    => 'Import Loans',
                'summary' => 'Upload and process DA loan data files in bulk.',
                'url'     => '/admin/da-system',
            ],
            [
                'name'    => 'View Loans',
                'summary' => 'Browse and search all DA system loan records.',
                'url'     => '/admin/da-system/loans',
            ],
        ];
    }

    public function index()
    {
        $jobs = CampaignsJobProvider::whereIn('from', ['da_system_data_upload', 'da_system_payment_upload', 'da_system_rps_upload'])
            ->orderBy('id', 'desc')
            ->limit(20)
            ->get(['id', 'payload', 'is_available', 'created_at']);

        return view('admin.da-system.index', compact('jobs'));
    }

    public function loans(Request $request)
    {
        $query = DaSystemData::query();

        if ($request->filled('search_name')) {
            $query->where('member_name', 'like', '%' . $request->get('search_name') . '%');
        }

        if ($request->filled('search_loan')) {
            $query->where('loan_no', 'like', '%' . $request->get('search_loan') . '%');
        }

        if ($request->filled('search_partner')) {
            $query->where('partner_id', 'like', '%' . $request->get('search_partner') . '%');
        }

        $loans = $query->orderBy('id', 'desc')
            ->paginate(25, [
                'id', 'partner_id', 'loan_no', 'member_name', 'status',
                 DB::raw('ROUND(outstanding_principal, 2) as outstanding_principal'), 'disbursement_date',
                'district', 'state', 'branch_name',
            ]);



        $metabase_data = (new Dashboard($request))->getMetabaseReport(['resource' => ["report_id" => 1265], 'type'=> 'question', 'params' => []]);
        
        return view('admin.da-system.loans', ['loans' => $loans, 'metabase_data' => $metabase_data->getData()->data]);
    }

    public function loanDetail($id)
    {
        $loan = DaSystemData::findOrFail($id);
        $documents = DB::table('blacksoil_documents')
            ->where('loan_id', $loan->loan_no)
            ->orderBy('id', 'desc')
            ->get();

        return view('admin.da-system.loan-detail', compact('loan', 'documents'));
    }

    public function viewDocument($id)
    {
        $document = DB::table('blacksoil_documents')->where('id', $id)->first();

        if (!$document) {
            abort(404, 'Document record not found');
        }

        $filePath = $document->file_path;

        if (!Storage::disk('s3')->exists($filePath)) {
            abort(404, 'File not found on S3');
        }

        $fileContent = Storage::disk('s3')->get($filePath);
        $fileName = !empty($document->file_name) ? $document->file_name : basename($filePath);
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));

        $mimeTypes = [
            'pdf'  => 'application/pdf',
            'png'  => 'image/png',
            'jpg'  => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'gif'  => 'image/gif',
            'webp' => 'image/webp',
            'csv'  => 'text/csv',
            'txt'  => 'text/plain',
            'doc'  => 'application/msword',
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'xls'  => 'application/vnd.ms-excel',
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        ];

        $mimeType = isset($mimeTypes[$ext]) ? $mimeTypes[$ext] : 'application/octet-stream';

        return response($fileContent, 200, [
            'Content-Type'        => $mimeType,
            'Content-Disposition' => 'inline; filename="' . $fileName . '"',
        ]);
    }

    public function import(Request $request)
    {
        try {
            if ($request->has('file') && $request->files->get('file') != null) {
                if (filesize($request->files->get('file')) > 18874368) {
                    Session::flash('error', 'Uploaded file is too large');
                    return redirect()->back();
                }
            }

            $date = Carbon::now()->toDateTimeString();
            $name = str_replace(' ', '_', $date) . '_' . time() . '_da_system_data.' . $request->file('file')->getClientOriginalExtension();

            $file_path = $this->saveFileToS3($request->file('file'), $name, 'da_system');

            $file_path_local = storage_path('cron_da_system');
            if (!file_exists($file_path_local)) {
                mkdir($file_path_local, 0777, true);
            }
            $request->file('file')->move($file_path_local, $name);

            $data = $request->all();
            $data['file_path'] = $file_path;
            $data['file_name'] = $name;
            $data['local_path'] = storage_path('cron_da_system') . '/' . $name;

            $jobs = new CampaignsJobProvider();
            $jobs->from = 'da_system_data_upload';
            $jobs->payload = json_encode($data);
            $jobs->available_at = $date;
            $jobs->application_id = 0;
            $jobs->created_at = $date;
            $jobs->is_available = 0;
            $jobs->save();

            Session::flash('success', 'File uploaded successfully. You will be notified once all data is processed.');
            return redirect()->back();
        } catch (\Exception $e) {
            Session::flash('error', 'Something went wrong: ' . $e->getMessage() . ' (line ' . $e->getLine() . ')');
            return redirect()->back();
        }
    }

    public function startFileProcess(Request $request)
    {
        $filePath = $request->get('file_path');
        try {
            $request->attributes->add(['file_path' => $filePath]);
            Excel::import(new DaSystemDataImport($request), $filePath, 's3');
            Storage::disk('s3')->delete($filePath);
        } catch (\Exception $e) {
            $cwFactory = new CloudWatchLoggerFactory();                                    
            $_data = [
                'process' => 'Direct Assignment Loan Upload',
                'status' => 'Error',
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            ];
            
            $cwFactory->logger(json_encode($_data));
        }
    }

    // ─── DA Payment Upload ───────────────────────────────────────────────────

    public function paymentUpload()
    {
        $jobs = CampaignsJobProvider::where('from', 'da_system_payment_upload')
            ->orderBy('id', 'desc')
            ->limit(20)
            ->get(['id', 'payload', 'is_available', 'created_at']);

        return view('admin.da-system.payment-upload', compact('jobs'));
    }

    public function paymentImport(Request $request)
    {
        try {
            if ($request->has('file') && $request->files->get('file') != null) {
                if (filesize($request->files->get('file')) > 18874368) {
                    Session::flash('error', 'Uploaded file is too large');
                    return redirect()->back();
                }
            }

            try {
                $client = new Client();
                $response = $client->request('POST', _env('PY_SCRIPT_SERVER_HOST').'/api/blacksoil_payments_upload', [
                    'timeout'   => 120,
                    'multipart' => [
                        [
                            'name'     => 'file',
                            'contents' => fopen($request->file('file')->getRealPath(), 'r'),
                            'filename' => $request->file('file')->getClientOriginalName(),
                        ],
                        [
                            'name'     => 'is_verify',
                            'contents' => '0',
                        ],
                    ],
                ]);

                $result = json_decode($response->getBody()->getContents(), true);
                if (isset($result['status']) && $result['status'] === 'FAILED') {
                    Session::flash('error', $result['message'] ?? 'Validation Failed');
                    return redirect()->back();
                }
            } catch (RequestException $e) {
                $body = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage();
                $result = json_decode($body, true);
                $errorMsg = (isset($result['detail']) ? $result['detail'] : (isset($result['message']) ? $result['message'] : 'Python microservice validation failed'));
                Session::flash('error', $errorMsg);
                return redirect()->back();
            }

            $date = Carbon::now()->toDateTimeString();
            $name = str_replace(' ', '_', $date) . '_' . time() . '_da_payment.' . $request->file('file')->getClientOriginalExtension();

            $file_path = $this->saveFileToS3($request->file('file'), $name, 'da_system_payments');

            $data = $request->all();
            $data['file_path'] = $file_path;
            $data['file_name'] = $name;

            $jobs = new CampaignsJobProvider();
            $jobs->from = 'da_system_payment_upload';
            $jobs->payload = json_encode($data);
            $jobs->available_at = $date;
            $jobs->application_id = 0;
            $jobs->created_at = $date;
            $jobs->is_available = 0;
            $jobs->save();

            Session::flash('success', 'Payment file uploaded successfully. It will be processed shortly.');
            return redirect()->back();
        } catch (\Exception $e) {
            Session::flash('error', 'Something went wrong: ' . $e->getMessage() . ' (line ' . $e->getLine() . ')');
            return redirect()->back();
        }
    }

    public function startDAPaymentFileProcess(Request $request)
    {
        $s3Path    = $request->get('file_path');
        $fileName  = $request->get('file_name');

        try {
            if (!$s3Path || !Storage::disk('s3')->exists($s3Path)) {
                throw new \Exception('S3 payment file not found: ' . $s3Path);
            }

            $fileContents = Storage::disk('s3')->get($s3Path);

            $client = new Client();
            $response = $client->request('POST', _env('PY_SCRIPT_SERVER_HOST').'/api/blacksoil_payments_upload', [
                'timeout'   => 120,
                'multipart' => [
                    [
                        'name'     => 'file',
                        'contents' => $fileContents,
                        'filename' => $fileName,
                    ],
                    [
                        'name'     => 'is_verify',
                        'contents' => '1',
                    ],
                ],
            ]);

            if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
                throw new \Exception('API returned status ' . $response->getStatusCode());
            }

            Storage::disk('s3')->delete($s3Path);
        } catch (RequestException $e) {
            $body = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage();
            (new Slack(new Request([
                'title'  => 'DA System payment file API call failed',
                'fields' => ['message' => $body, 'file' => $fileName],
                'group'  => Slack::$STAGE_TESTING,
            ])))->send();
        } catch (\Exception $e) {
            (new Slack(new Request([
                'title'  => 'DA System payment file could not be processed',
                'fields' => [
                    'message' => $e->getMessage(),
                    'line'    => $e->getLine(),
                    'file'    => $e->getFile(),
                ],
                'group'  => Slack::$STAGE_TESTING,
            ])))->send();
        }
    }


    public function rpsImport(Request $request)
    {
        try {
            if ($request->has('file') && $request->files->get('file') != null) {
                if (filesize($request->files->get('file')) > 18874368) {
                    Session::flash('error', 'Uploaded file is too large');
                    return redirect()->back();
                }
            }

            try {
                $client = new Client();
                $response = $client->request('POST', _env('PY_SCRIPT_SERVER_HOST').'/api/blacksoil_rps_upload', [
                    'timeout'   => 120,
                    'multipart' => [
                        [
                            'name'     => 'file',
                            'contents' => fopen($request->file('file')->getRealPath(), 'r'),
                            'filename' => $request->file('file')->getClientOriginalName(),
                        ],
                        [
                            'name'     => 'is_verify',
                            'contents' => '0',
                        ],
                    ],
                ]);

                $result = json_decode($response->getBody()->getContents(), true);
                if (isset($result['status']) && $result['status'] === 'FAILED') {
                    Session::flash('error', $result['message'] ?? 'Validation Failed');
                    return redirect()->back();
                }
            } catch (RequestException $e) {
                $body = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage();
                $result = json_decode($body, true);
                $errorMsg = (isset($result['detail']) ? $result['detail'] : (isset($result['message']) ? $result['message'] : 'Python microservice validation failed'));
                Session::flash('error', $errorMsg);
                return redirect()->back();
            }

            $date = Carbon::now()->toDateTimeString();
            $name = str_replace(' ', '_', $date) . '_' . time() . '_da_rps.' . $request->file('file')->getClientOriginalExtension();

            $file_path = $this->saveFileToS3($request->file('file'), $name, 'da_system_rps');

            $data = $request->all();
            $data['file_path'] = $file_path;
            $data['file_name'] = $name;

            $jobs = new CampaignsJobProvider();
            $jobs->from = 'da_system_rps_upload';
            $jobs->payload = json_encode($data);
            $jobs->available_at = $date;
            $jobs->application_id = 0;
            $jobs->created_at = $date;
            $jobs->is_available = 0;
            $jobs->save();

            Session::flash('success', 'RPS file uploaded successfully. It will be processed shortly.');
            return redirect()->back();
        } catch (\Exception $e) {
            Session::flash('error', 'Something went wrong: ' . $e->getMessage() . ' (line ' . $e->getLine() . ')');
            return redirect()->back();
        }
    }

    public function startDARPSFileProcess(Request $request)
    {
        $s3Path    = $request->get('file_path');
        $fileName  = $request->get('file_name');

        try {
            if (!$s3Path || !Storage::disk('s3')->exists($s3Path)) {
                throw new \Exception('S3 rps file not found: ' . $s3Path);
            }

            $fileContents = Storage::disk('s3')->get($s3Path);

            
            $client = new Client();
            $response = $client->request('POST', _env('PY_SCRIPT_SERVER_HOST').'/api/blacksoil_rps_upload', [
                'timeout'   => 120,
                'multipart' => [
                    [
                        'name'     => 'file',
                        'contents' => $fileContents,
                        'filename' => $fileName,
                    ],
                    [
                        'name'     => 'is_verify',
                        'contents' => '1',
                    ],
                ],
            ]);

            var_dump($response->getBody()->getContents());

            if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
                throw new \Exception('API returned status ' . $response->getStatusCode());
            }

            Storage::disk('s3')->delete($s3Path);
        } catch (RequestException $e) {
            $body = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage();
            var_dump($body);
            (new Slack(new Request([
                'title'  => 'DA System rps file API call failed',
                'fields' => ['message' => $body, 'file' => $fileName],
                'group'  => Slack::$STAGE_TESTING,
            ])))->send();
        } catch (\Exception $e) {
            var_dump($e->getMessage());
            (new Slack(new Request([
                'title'  => 'DA System rps file could not be processed',
                'fields' => [
                    'message' => $e->getMessage(),
                    'line'    => $e->getLine(),
                    'file'    => $e->getFile(),
                ],
                'group'  => Slack::$STAGE_TESTING,
            ])))->send();
        }
    }

    // ─── Shared ──────────────────────────────────────────────────────────────

    private function saveFileToS3($file, $fileName, $folder)
    {
        $s3 = Storage::disk('s3');
        $file_path = '/' . $folder . '/' . $fileName;
        $s3->put($file_path, $file);
        $files = $s3->listContents($file_path);
        return $files[0]['path'];
    }
}
