<?php

namespace App\Services\Mentorship;

use App\Models\Mentorship\Certificate;
use App\Models\Mentorship\Assignment;
use App\Models\Mentorship\Programme;
use App\Models\User;
use App\Services\EmailService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Barryvdh\DomPDF\Facade\Pdf;
use Carbon\Carbon;

class CertificateService
{
    protected EmailService $emailService;

    public function __construct(EmailService $emailService)
    {
        $this->emailService = $emailService;
    }

    /**
     * Generate a certificate for an assignment.
     */
    public function generate(Assignment $assignment, ?int $generatedBy = null): Certificate
    {
        DB::beginTransaction();
        
        try {
            // Check if assignment is eligible for certificate
            if (!$assignment->certificate_eligible) {
                throw new \Exception('This assignment is not eligible for a certificate.');
            }

            // Check if certificate already exists
            if ($assignment->certificate && $assignment->certificate->status === Certificate::STATUS_ACTIVE) {
                throw new \Exception('A certificate already exists for this assignment.');
            }

            // Get programme and user details
            $programme = $assignment->programme;
            $mentee = $assignment->mentee;
            $mentor = $assignment->mentor;

            // Generate certificate data
            $certificateData = [
                'assignment_id' => $assignment->id,
                'programme_id' => $programme->id,
                'user_id' => $mentee->id,
                'certificate_number' => Certificate::generateCertificateNumber(),
                'verification_code' => Certificate::generateVerificationCode(),
                'recipient_name' => $mentee->name,
                'programme_name' => $programme->title,
                'description' => $this->generateDescription($assignment),
                'skills_acquired' => $assignment->goals ? explode("\n", $assignment->goals) : null,
                'orientation' => $programme->certificate_orientation ?? Certificate::ORIENTATION_LANDSCAPE,
                'template' => $programme->certificate_template ?? 'default',
                'completion_date' => $assignment->completed_at ? $assignment->completed_at->toDateString() : now()->toDateString(),
                'issue_date' => now()->toDateString(),
                'organization_name' => config('app.name', 'Mentorship Platform'),
                'organization_address' => config('app.address', ''),
                'organization_seal' => config('mentorship.certificate_seal'),
                'organization_logo' => config('mentorship.certificate_logo'),
                'signatory_name' => config('mentorship.certificate_signatory_name'),
                'signatory_title' => config('mentorship.certificate_signatory_title'),
                'signatory_signature' => config('mentorship.certificate_signatory_signature'),
                'mentor_name' => $mentor->name,
                'mentor_signature' => null, // Would need mentor signature storage
                'generated_by' => $generatedBy ?? auth()->id(),
                'generated_at' => now(),
                'generation_ip' => request()->ip(),
                'status' => Certificate::STATUS_ACTIVE,
            ];

            $certificate = Certificate::create($certificateData);

            // Generate PDF
            $pdfData = $this->generatePdf($certificate);
            $certificate->setFileInfo(
                $pdfData['path'],
                $pdfData['name'],
                'pdf',
                $pdfData['size']
            );

            // Mark assignment as certificate issued
            $assignment->update(['certificate_issued' => true]);

            DB::commit();

            // Send certificate notification
            $this->sendCertificateNotification($certificate);

            Log::info('Mentorship certificate generated', [
                'certificate_id' => $certificate->id,
                'certificate_number' => $certificate->certificate_number,
                'assignment_id' => $assignment->id,
                'user_id' => $mentee->id,
                'generated_by' => $certificate->generated_by,
            ]);

            return $certificate;
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to generate mentorship certificate', [
                'error' => $e->getMessage(),
                'assignment_id' => $assignment->id,
            ]);
            throw $e;
        }
    }

    /**
     * Regenerate certificate PDF.
     */
    public function regeneratePdf(Certificate $certificate): Certificate
    {
        DB::beginTransaction();
        
        try {
            $pdfData = $this->generatePdf($certificate);
            $certificate->setFileInfo(
                $pdfData['path'],
                $pdfData['name'],
                'pdf',
                $pdfData['size']
            );

            DB::commit();

            Log::info('Certificate PDF regenerated', [
                'certificate_id' => $certificate->id,
            ]);

            return $certificate->fresh();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to regenerate certificate PDF', [
                'error' => $e->getMessage(),
                'certificate_id' => $certificate->id,
            ]);
            throw $e;
        }
    }

    /**
     * Revoke a certificate.
     */
    public function revoke(Certificate $certificate, int $revokedBy, string $reason): Certificate
    {
        DB::beginTransaction();
        
        try {
            $certificate->revoke($revokedBy, $reason);

            DB::commit();

            Log::info('Certificate revoked', [
                'certificate_id' => $certificate->id,
                'revoked_by' => $revokedBy,
                'reason' => $reason,
            ]);

            return $certificate->fresh();
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to revoke certificate', [
                'error' => $e->getMessage(),
                'certificate_id' => $certificate->id,
            ]);
            throw $e;
        }
    }

    /**
     * Verify a certificate by verification code.
     */
    public function verifyByCode(string $code): ?Certificate
    {
        $certificate = Certificate::where('verification_code', $code)->first();

        if ($certificate) {
            $certificate->recordVerification();

            Log::info('Certificate verified', [
                'certificate_id' => $certificate->id,
                'certificate_number' => $certificate->certificate_number,
                'verification_code' => $code,
            ]);
        }

        return $certificate;
    }

    /**
     * Get certificate file path for download.
     */
    public function getDownloadPath(Certificate $certificate): ?string
    {
        if (!$certificate->file_path || !Storage::exists($certificate->file_path)) {
            // Regenerate PDF if file doesn't exist
            $this->regeneratePdf($certificate);
        }

        // Record download
        $certificate->recordDownload(request()->ip());

        return $certificate->file_path;
    }

    /**
     * Get certificates for a user.
     */
    public function getForUser(int $userId, int $perPage = 12)
    {
        return Certificate::with(['programme', 'assignment'])
            ->where('user_id', $userId)
            ->where('status', Certificate::STATUS_ACTIVE)
            ->orderBy('issue_date', 'desc')
            ->paginate($perPage);
    }

    /**
     * Get all certificates with filtering.
     */
    public function getCertificates(array $filters = [], int $perPage = 15)
    {
        $query = Certificate::with(['user', 'programme', 'assignment', 'generator']);

        // Filter by status
        if (!empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        // Filter by programme
        if (!empty($filters['programme_id'])) {
            $query->where('programme_id', $filters['programme_id']);
        }

        // Filter by user
        if (!empty($filters['user_id'])) {
            $query->where('user_id', $filters['user_id']);
        }

        // Search by certificate number or recipient name
        if (!empty($filters['search'])) {
            $query->where(function ($q) use ($filters) {
                $q->where('certificate_number', 'like', '%' . $filters['search'] . '%')
                    ->orWhere('recipient_name', 'like', '%' . $filters['search'] . '%');
            });
        }

        // Sort
        $sortBy = $filters['sort_by'] ?? 'generated_at';
        $sortOrder = $filters['sort_order'] ?? 'desc';
        $query->orderBy($sortBy, $sortOrder);

        return $query->paginate($perPage);
    }

    /**
     * Generate description for certificate.
     */
    protected function generateDescription(Assignment $assignment): string
    {
        $programme = $assignment->programme;
        $mentee = $assignment->mentee;
        $mentor = $assignment->mentor;

        return "This is to certify that {$mentee->name} has successfully completed the mentorship programme " .
            "\"{$programme->title}\" under the guidance of {$mentor->name}. " .
            "The programme covered a duration of {$assignment->duration_days} days " .
            "with {$assignment->sessions_completed} completed mentorship sessions.";
    }

    /**
     * Generate PDF for certificate.
     */
    protected function generatePdf(Certificate $certificate): array
    {
        $template = 'mentorship.certificates.templates.' . ($certificate->template ?? 'default');
        
        // Check if custom template exists
        $templatePath = resource_path('views/mentorship/certificates/templates/' . ($certificate->template ?? 'default') . '.blade.php');
        if (!file_exists($templatePath)) {
            $template = 'mentorship.certificates.templates.default';
        }

        // Generate PDF
        $pdf = Pdf::loadView($template, [
            'certificate' => $certificate,
            'orientation' => $certificate->orientation,
        ]);

        // Set paper size and orientation
        $pdf->setPaper('A4', $certificate->orientation);

        // Generate file name and path
        $fileName = 'certificate-' . $certificate->certificate_number . '.pdf';
        $directory = 'mentorship/certificates/' . date('Y/m');
        $filePath = $directory . '/' . $fileName;

        // Ensure directory exists
        Storage::makeDirectory($directory);

        // Save PDF
        Storage::put($filePath, $pdf->output());

        // Get file size
        $fileSize = Storage::size($filePath);

        return [
            'path' => $filePath,
            'name' => $fileName,
            'size' => $fileSize,
        ];
    }

    /**
     * Send certificate notification.
     */
    protected function sendCertificateNotification(Certificate $certificate): void
    {
        try {
            if ($this->emailService->isReady()) {
                $this->emailService->sendTemplate(
                    $certificate->user->email,
                    'Your Mentorship Certificate is Ready - ' . $certificate->programme_name,
                    'emails.mentorship.certificate-ready',
                    [
                        'userName' => $certificate->recipient_name,
                        'programmeName' => $certificate->programme_name,
                        'certificateNumber' => $certificate->certificate_number,
                        'verificationUrl' => $certificate->verification_url,
                        'downloadUrl' => route('mentorship.certificates.download', $certificate),
                        'dashboardUrl' => route('dashboard'),
                    ]
                );
            }
        } catch (\Exception $e) {
            Log::error('Failed to send certificate notification', [
                'certificate_id' => $certificate->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Bulk generate certificates for completed assignments.
     */
    public function bulkGenerate(int $programmeId, ?int $generatedBy = null): array
    {
        $assignments = Assignment::where('programme_id', $programmeId)
            ->where('certificate_eligible', true)
            ->where('certificate_issued', false)
            ->get();

        $generated = [];
        $failed = [];

        foreach ($assignments as $assignment) {
            try {
                $certificate = $this->generate($assignment, $generatedBy);
                $generated[] = $certificate;
            } catch (\Exception $e) {
                $failed[] = [
                    'assignment_id' => $assignment->id,
                    'error' => $e->getMessage(),
                ];
            }
        }

        Log::info('Bulk certificate generation completed', [
            'programme_id' => $programmeId,
            'generated_count' => count($generated),
            'failed_count' => count($failed),
        ]);

        return [
            'generated' => $generated,
            'failed' => $failed,
            'total' => $assignments->count(),
        ];
    }
}
