<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\BulkUploadCompanyRegistrationRequest;
use App\Http\Requests\SendInvitationRequest;
use App\Http\Requests\UpdateCompanyRegistrationRequest;
use App\Models\AuditLog;
use App\Models\CompanyRegistration;
use App\Services\AmlScreeningService;
use App\Services\AuditService;
use App\Services\BulkRegistrationUploadService;
use App\Services\CompanyRegistrationService;
use App\Services\RegistrationFileUploadService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;

class CompanyRegistrationController extends Controller
{
    public function __construct(
        private readonly CompanyRegistrationService $registrationService,
        private readonly RegistrationFileUploadService $fileUploadService,
        private readonly BulkRegistrationUploadService $bulkUploadService,
        private readonly AuditService $auditService,
        private readonly AmlScreeningService $amlScreeningService,
    ) {}

    /**
     * Get all pending Company registrations.
     */
    public function pending(Request $request): JsonResponse
    {
        try {
            $perPage = (int) $request->input('per_page', 15);
            $perPage = min(max($perPage, 1), 100);

            $submissions = $this->registrationService->getPendingSubmissions($perPage);

            return response()->json([
                'success' => true,
                'data' => $submissions->items() ? collect($submissions->items())->map(fn ($submission) => [
                    'id' => $submission->id,
                    'company_name' => $submission->company_name,
                    'email_address' => $submission->email_address,
                    'phone_number' => $submission->phone_number,
                    'country' => $submission->country,
                    'state' => $submission->state,
                    'city' => $submission->city,
                    'submission_type' => $submission->submission_type,
                    'status' => $submission->status,
                    'account_status' => $submission->account_status,
                    'verification_status' => $submission->verification_status,
                    'submitted_at' => $submission->created_at->toIso8601String(),
                ]) : [],
                'pagination' => [
                    'current_page' => $submissions->currentPage(),
                    'last_page' => $submissions->lastPage(),
                    'per_page' => $submissions->perPage(),
                    'total' => $submissions->total(),
                    'from' => $submissions->firstItem() ?? 0,
                    'to' => $submissions->lastItem() ?? 0,
                ],
            ]);
        } catch (\Exception $e) {
            Log::error('Error fetching pending Company registrations: ' . $e->getMessage(), [
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching pending submissions.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Get all Company registrations with optional filters.
     */
    public function index(Request $request): JsonResponse
    {
        try {
            $perPage = (int) $request->input('per_page', 15);
            $perPage = min(max($perPage, 1), 100);

            $filters = [];
            if ($request->has('status')) {
                $filters['status'] = $request->input('status');
            }
            if ($request->has('submission_type')) {
                $filters['submission_type'] = $request->input('submission_type');
            }
            if ($request->has('account_status')) {
                $filters['account_status'] = $request->input('account_status');
            }
            if ($request->has('verification_status')) {
                $filters['verification_status'] = $request->input('verification_status');
            }
            if ($request->has('from_date')) {
                $filters['from_date'] = $request->input('from_date');
            }
            if ($request->has('to_date')) {
                $filters['to_date'] = $request->input('to_date');
            }

            $submissions = $this->registrationService->getAllSubmissions($filters, $perPage);

            return response()->json([
                'success' => true,
                'data' => $submissions->items() ? collect($submissions->items())->map(fn ($submission) => [
                    'id' => $submission->id,
                    'company_name' => $submission->company_name,
                    'email_address' => $submission->email_address,
                    'phone_number' => $submission->phone_number,
                    'country' => $submission->country,
                    'state' => $submission->state,
                    'city' => $submission->city,
                    'submission_type' => $submission->submission_type,
                    'status' => $submission->status,
                    'account_status' => $submission->account_status,
                    'verification_status' => $submission->verification_status,
                    'submitted_at' => $submission->created_at->toIso8601String(),
                    'approved_at' => $submission->approved_at?->toIso8601String(),
                    'rejected_at' => $submission->rejected_at?->toIso8601String(),
                ]) : [],
                'pagination' => [
                    'current_page' => $submissions->currentPage(),
                    'last_page' => $submissions->lastPage(),
                    'per_page' => $submissions->perPage(),
                    'total' => $submissions->total(),
                    'from' => $submissions->firstItem() ?? 0,
                    'to' => $submissions->lastItem() ?? 0,
                ],
            ]);
        } catch (\Exception $e) {
            Log::error('Error fetching Company registrations: ' . $e->getMessage(), [
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching submissions.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Get a specific Company registration.
     */
    public function show(CompanyRegistration $registration, Request $request): JsonResponse
    {
        try {
            $registration = $this->registrationService->getSubmission($registration);

            $this->auditService->success(
                AuditLog::ACTION_COMPANY_REGISTRATION_VIEWED,
                AuditLog::ACTOR_ADMIN,
                $request->user()->id,
                $request->user()->email,
                'CompanyRegistration', $registration->id,
                ['company_name' => $registration->company_name],
                $request->ip(),
            );

            return response()->json([
                'success' => true,
                'data' => [
                    'id' => $registration->id,
                    'company_id' => $registration->company_id,
                    'submission_type' => $registration->submission_type,
                    'status' => $registration->status,
                    'account_status' => $registration->account_status,
                    'verification_status' => $registration->verification_status,
                    'rejection_reason' => $registration->rejection_reason,
                    // Company Information
                    'company_name' => $registration->company_name,
                    'rc_number' => $registration->rc_number,
                    'country' => $registration->country,
                    'state' => $registration->state,
                    'city' => $registration->city,
                    'phone_number' => $registration->phone_number,
                    'secondary_phone' => $registration->secondary_phone,
                    'email_address' => $registration->email_address,
                    'house_address' => $registration->house_address,
                    'previous_address' => $registration->previous_address,
                    // Director Information
                    'director_name' => $registration->director_name,
                    'identity_card_type' => $registration->identity_card_type,
                    'identity_card_number' => $registration->identity_card_number,
                    // Document URLs
                    'documents' => [
                        'director_identity_cards' => $this->fileUploadService->getDocumentUrl($registration->director_identity_cards_path),
                        'cac_document' => $this->fileUploadService->getDocumentUrl($registration->cac_document_path),
                        'director_passport_photograph' => $this->fileUploadService->getDocumentUrl($registration->director_passport_photograph_path),
                    ],
                    // Tracking
                    'consent_given' => $registration->consent_given,
                    'submitted_at' => $registration->created_at?->toIso8601String(),
                    'approved_at' => $registration->approved_at?->toIso8601String(),
                    'rejected_at' => $registration->rejected_at?->toIso8601String(),
                    'approved_by' => $registration->approvedBy ? [
                        'id' => $registration->approvedBy->id,
                        'name' => $registration->approvedBy->name,
                    ] : null,
                    'rejected_by' => $registration->rejectedBy ? [
                        'id' => $registration->rejectedBy->id,
                        'name' => $registration->rejectedBy->name,
                    ] : null,
                ],
            ]);
        } catch (\Exception $e) {
            Log::error('Error fetching Company registration: ' . $e->getMessage(), [
                'registration_id' => $registration->id,
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching the submission.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Update a Company registration.
     */
    public function update(UpdateCompanyRegistrationRequest $request, CompanyRegistration $registration): JsonResponse
    {
        try {
            // Check if rejected
            if ($registration->isRejected()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot update a rejected submission.',
                ], 422);
            }

            $validated = $request->validated();

            // Handle file uploads if present
            if ($request->hasFile('director_identity_cards')) {
                $validated['director_identity_cards_path'] = $this->fileUploadService->uploadDocument(
                    $request->file('director_identity_cards'),
                    'director_identity_cards'
                );
                unset($validated['director_identity_cards']);
            }

            if ($request->hasFile('cac_document')) {
                $validated['cac_document_path'] = $this->fileUploadService->uploadDocument(
                    $request->file('cac_document'),
                    'cac_document'
                );
                unset($validated['cac_document']);
            }

            if ($request->hasFile('director_passport_photograph')) {
                $validated['director_passport_photograph_path'] = $this->fileUploadService->uploadDocument(
                    $request->file('director_passport_photograph'),
                    'director_passport_photograph'
                );
                unset($validated['director_passport_photograph']);
            }

            $updatedRegistration = $this->registrationService->updateSubmission(
                $registration,
                $validated
            );

            $this->auditService->success(
                AuditLog::ACTION_COMPANY_REGISTRATION_UPDATED,
                AuditLog::ACTOR_ADMIN,
                $request->user()->id,
                $request->user()->email,
                'CompanyRegistration', $updatedRegistration->id,
                ['company_name' => $updatedRegistration->company_name, 'fields_updated' => array_keys($validated)],
                $request->ip(),
            );

            return response()->json([
                'success' => true,
                'message' => 'Company registration updated successfully.',
                'data' => [
                    'id' => $updatedRegistration->id,
                    'company_name' => $updatedRegistration->company_name,
                    'email_address' => $updatedRegistration->email_address,
                    'phone_number' => $updatedRegistration->phone_number,
                    'status' => $updatedRegistration->status,
                ],
            ]);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('Error updating Company registration: ' . $e->getMessage(), [
                'registration_id' => $registration->id,
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while updating the submission.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Approve a Company registration.
     */
    public function approve(CompanyRegistration $registration, Request $request): JsonResponse
    {
        try {
            // Check if already approved
            if ($registration->isApproved()) {
                return response()->json([
                    'success' => false,
                    'message' => 'This submission has already been approved.',
                ], 422);
            }

            // Check if already rejected
            if ($registration->isRejected()) {
                return response()->json([
                    'success' => false,
                    'message' => 'This submission has been rejected and cannot be approved.',
                ], 422);
            }

            $updatedRegistration = $this->registrationService->approveSubmission($registration, $request->user()->id);

            $this->auditService->success(
                AuditLog::ACTION_COMPANY_REGISTRATION_APPROVED,
                AuditLog::ACTOR_ADMIN,
                $request->user()->id,
                $request->user()->email,
                'CompanyRegistration', $updatedRegistration->id,
                ['company_name' => $updatedRegistration->company_name],
                $request->ip(),
            );

            return response()->json([
                'success' => true,
                'message' => 'Company registration approved successfully. You can now send an invitation to create their account.',
                'data' => [
                    'id' => $updatedRegistration->id,
                    'company_name' => $updatedRegistration->company_name,
                    'email_address' => $updatedRegistration->email_address,
                    'status' => $updatedRegistration->status,
                    'account_status' => $updatedRegistration->account_status,
                    'approved_at' => $updatedRegistration->approved_at->toIso8601String(),
                ],
            ]);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('Error approving Company registration: ' . $e->getMessage(), [
                'registration_id' => $registration->id,
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while approving the submission.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Send invitation to Company registration.
     * Approves the registration, creates company account and portal user, then sends invitation email.
     */
    public function sendInvitation(CompanyRegistration $registration, SendInvitationRequest $request): JsonResponse
    {
        try {
            // Check if already rejected
            if ($registration->isRejected()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Cannot send invitation to a rejected registration.',
                ], 422);
            }

            // Check if already invited or active
            if ($registration->isAccountInvited() || $registration->isAccountActive()) {
                return response()->json([
                    'success' => false,
                    'message' => 'Invitation has already been sent or account is already active.',
                ], 422);
            }

            $validated = $request->validated();
            $email = $validated['email'] ?? null;

            $company = $this->registrationService->sendInvitation($registration, $email, $request->user()->id);

            $this->auditService->success(
                AuditLog::ACTION_COMPANY_INVITATION_SENT,
                AuditLog::ACTOR_ADMIN,
                $request->user()->id,
                $request->user()->email,
                'CompanyRegistration', $registration->id,
                ['company_name' => $company->name, 'invited_email' => $company->email],
                $request->ip(),
            );

            return response()->json([
                'success' => true,
                'message' => 'Registration approved and invitation sent successfully. Company account created and invitation email sent.',
                'data' => [
                    'submission_id' => $registration->fresh()->id,
                    'company_id' => $company->id,
                    'company_name' => $company->name,
                    'company_email' => $company->email,
                    'status' => $registration->fresh()->status,
                    'account_status' => $registration->fresh()->account_status,
                ],
            ]);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('Error sending Company registration invitation: ' . $e->getMessage(), [
                'registration_id' => $registration->id,
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while sending the invitation.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Reject a Company registration.
     */
    public function reject(CompanyRegistration $registration, Request $request): JsonResponse
    {
        try {
            // Validate rejection reason
            $validated = $request->validate([
                'rejection_reason' => ['nullable', 'string', 'max:1000'],
            ]);

            // Check if already approved
            if ($registration->isApproved()) {
                return response()->json([
                    'success' => false,
                    'message' => 'This submission has already been approved and cannot be rejected.',
                ], 422);
            }

            // Check if already rejected
            if ($registration->isRejected()) {
                return response()->json([
                    'success' => false,
                    'message' => 'This submission has already been rejected.',
                ], 422);
            }

            $registration = $this->registrationService->rejectSubmission(
                $registration,
                $request->user()->id,
                $validated['rejection_reason'] ?? null
            );

            $this->auditService->success(
                AuditLog::ACTION_COMPANY_REGISTRATION_REJECTED,
                AuditLog::ACTOR_ADMIN,
                $request->user()->id,
                $request->user()->email,
                'CompanyRegistration', $registration->id,
                ['company_name' => $registration->company_name, 'reason' => $registration->rejection_reason],
                $request->ip(),
            );

            return response()->json([
                'success' => true,
                'message' => 'Company registration rejected successfully. Rejection email sent.',
                'data' => [
                    'submission_id' => $registration->id,
                    'company_name' => $registration->company_name,
                    'rejection_reason' => $registration->rejection_reason,
                    'rejected_at' => $registration->rejected_at->toIso8601String(),
                ],
            ]);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('Error rejecting Company registration: ' . $e->getMessage(), [
                'registration_id' => $registration->id,
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while rejecting the submission.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Export Company registrations to CSV.
     */
    public function exportCsv(Request $request)
    {
        $filters = [];
        if ($request->has('status'))              $filters['status']              = $request->input('status');
        if ($request->has('submission_type'))     $filters['submission_type']     = $request->input('submission_type');
        if ($request->has('account_status'))      $filters['account_status']      = $request->input('account_status');
        if ($request->has('verification_status')) $filters['verification_status'] = $request->input('verification_status');
        if ($request->has('from_date'))           $filters['from_date']           = $request->input('from_date');
        if ($request->has('to_date'))             $filters['to_date']             = $request->input('to_date');

        $submissions = $this->registrationService->getSubmissionsForExport($filters);

        $filename = 'company-registrations-' . now()->format('Y-m-d') . '.csv';

        $headers = [
            'Content-Type'        => 'text/csv',
            'Content-Disposition' => "attachment; filename=\"{$filename}\"",
        ];

        $columns = ['ID', 'Company Name', 'Email', 'Phone', 'Country', 'State', 'City', 'Submission Type', 'Status', 'Account Status', 'Verification Status', 'Submitted At', 'Approved At', 'Rejected At'];

        return response()->streamDownload(function () use ($submissions, $columns) {
            $handle = fopen('php://output', 'w');
            fputcsv($handle, $columns);

            foreach ($submissions as $row) {
                fputcsv($handle, [
                    $row->id,
                    $row->company_name,
                    $row->email_address,
                    $row->phone_number,
                    $row->country,
                    $row->state,
                    $row->city,
                    $row->submission_type,
                    $row->status,
                    $row->account_status,
                    $row->verification_status,
                    $row->created_at?->toIso8601String(),
                    $row->approved_at?->toIso8601String(),
                    $row->rejected_at?->toIso8601String(),
                ]);
            }

            fclose($handle);
        }, $filename, $headers);
    }

    /**
     * Bulk upload companies via CSV.
     */
    public function bulkUpload(BulkUploadCompanyRegistrationRequest $request): JsonResponse
    {
        try {
            $csvFile = $request->file('csv_file');
            $sendInvitations = $request->input('send_invitations', false);

            // Store CSV temporarily
            $csvPath = $csvFile->getRealPath();
            $originalFilename = $csvFile->getClientOriginalName();

            // Process CSV
            $results = $this->bulkUploadService->processCsvUpload($csvPath, $sendInvitations, $originalFilename);

            $this->auditService->success(
                AuditLog::ACTION_COMPANY_BULK_UPLOAD,
                AuditLog::ACTOR_ADMIN,
                $request->user()->id,
                $request->user()->email,
                null, null,
                ['total' => $results['total_rows'], 'success' => $results['successful_count'], 'failed' => $results['failed_count'], 'filename' => $originalFilename],
                $request->ip(),
            );

            $statusCode = $results['failed_count'] > 0 ? 207 : 201; // 207 Multi-Status if there are failures

            return response()->json([
                'success' => true,
                'message' => sprintf(
                    'Bulk upload completed. %d successful, %d failed out of %d total rows.',
                    $results['successful_count'],
                    $results['failed_count'],
                    $results['total_rows']
                ),
                'data' => [
                    'summary' => [
                        'total_rows' => $results['total_rows'],
                        'successful_count' => $results['successful_count'],
                        'failed_count' => $results['failed_count'],
                    ],
                    'successful' => $results['successful'],
                    'failed' => $results['failed'],
                ],
            ], $statusCode);
        } catch (\Exception $e) {
            Log::error('Error processing bulk CSV upload: ' . $e->getMessage(), [
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while processing the CSV file.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Run AML/PEP screening for a company registration (screens the director).
     */
    public function amlScreen(CompanyRegistration $registration, Request $request): JsonResponse
    {
        try {
            $screening = $this->amlScreeningService->screenCompanyRegistration(
                $registration,
                $request->user()->id
            );

            return response()->json([
                'success' => true,
                'message' => 'AML screening completed.',
                'data'    => $this->formatScreeningResult($screening),
            ]);
        } catch (\RuntimeException $e) {
            $serviceDown = $e->serviceUnavailable ?? false;
            return response()->json(array_filter([
                'success'      => false,
                'service_down' => $serviceDown ?: null,
                'message'      => $e->getMessage(),
            ]), $serviceDown ? 503 : 422);
        } catch (\Exception $e) {
            Log::error('Error running AML screening for company registration: ' . $e->getMessage(), [
                'registration_id' => $registration->id,
                'exception'       => $e,
            ]);
            return response()->json([
                'success' => false,
                'message' => 'An error occurred while running AML screening.',
                'error'   => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    private function formatScreeningResult(\App\Models\AmlScreeningResult $screening): array
    {
        return [
            'id'             => $screening->id,
            'risk_level'     => $screening->risk_level,
            'match_status'   => $screening->match_status,
            'total_results'  => $screening->total_results,
            'total_articles' => $screening->total_articles,
            'results'        => $screening->results,
            'screened_at'    => $screening->screened_at->toIso8601String(),
        ];
    }
}
