<?php

namespace App\Http\Controllers\Student;

use App\Http\Controllers\Controller;
use App\Models\Book;
use App\Models\BookChapter;
use App\Models\BookNote;
use App\Models\BookProgress;
use App\Models\Bookmark;
use App\Models\Enrollment;
use App\Models\FeePayment;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;

class BookController extends Controller
{
    /**
     * Display a listing of books.
     */
    public function index()
    {
        $books = Book::where('is_active', true)
            ->orderBy('order')
            ->with(['chapters'])
            ->get();

        return view('student.books.index', compact('books'));
    }

    /**
     * Display the specified book with chapters.
     */
    public function show(Book $book)
    {
        $book->load(['chapters' => function($query) {
            $query->orderBy('order');
        }]);

        // Get user progress
        $progress = BookProgress::where('user_id', Auth::id())
            ->where('book_id', $book->id)
            ->get()
            ->keyBy('book_chapter_id');

        // Get user bookmarks
        $bookmarks = Bookmark::where('user_id', Auth::id())
            ->where('book_id', $book->id)
            ->with('chapter')
            ->get();

        // Calculate overall progress
        $totalChapters = $book->chapters->count();
        $completedChapters = $progress->where('is_completed', true)->count();
        $overallProgress = $totalChapters > 0 ? ($completedChapters / $totalChapters) * 100 : 0;

        return view('student.books.show', compact('book', 'progress', 'bookmarks', 'overallProgress'));
    }

    /**
     * Display a specific chapter for reading.
     */
    public function readChapter(Book $book, BookChapter $chapter)
    {
        // Verify chapter belongs to book
        if ($chapter->book_id !== $book->id) {
            abort(404);
        }

        $book->load('chapters');
        
        // Get all chapters for navigation
        $allChapters = $book->chapters->sortBy('order');
        $currentIndex = $allChapters->search(function($item) use ($chapter) {
            return $item->id === $chapter->id;
        });

        $previousChapter = $allChapters->values()->get($currentIndex - 1);
        $nextChapter = $allChapters->values()->get($currentIndex + 1);

        // Get user notes for this chapter
        $notes = BookNote::where('user_id', Auth::id())
            ->where('book_chapter_id', $chapter->id)
            ->orderBy('created_at', 'desc')
            ->get();

        // Get user bookmarks for this chapter
        $bookmarks = Bookmark::where('user_id', Auth::id())
            ->where('book_chapter_id', $chapter->id)
            ->orderBy('position')
            ->get();

        // Get or create progress
        $progress = BookProgress::firstOrCreate(
            [
                'user_id' => Auth::id(),
                'book_id' => $book->id,
                'book_chapter_id' => $chapter->id,
            ],
            [
                'last_page_position' => 0,
                'is_completed' => false,
            ]
        );

        // Read the chapter HTML file
        $filePath = public_path($book->folder_path . '/' . $chapter->file_name);
        
        if (!File::exists($filePath)) {
            abort(404, 'Chapter file not found');
        }

        $htmlContent = File::get($filePath);
        
        // Extract only the body content (remove head, html tags, etc.)
        // Use DOMDocument to parse and extract content
        $dom = new \DOMDocument();
        @$dom->loadHTML(mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'));
        
        // Get the chapter-container div content
        $xpath = new \DOMXPath($dom);
        $container = $xpath->query('//div[@class="chapter-container"]')->item(0);
        
        if ($container) {
            $chapterContent = '';
            foreach ($container->childNodes as $node) {
                $chapterContent .= $dom->saveHTML($node);
            }
        } else {
            // Fallback: extract body content
            $body = $dom->getElementsByTagName('body')->item(0);
            if ($body) {
                $chapterContent = '';
                foreach ($body->childNodes as $node) {
                    $chapterContent .= $dom->saveHTML($node);
                }
            } else {
                $chapterContent = $htmlContent;
            }
        }

        // Replace HTML file links with Laravel routes
        $chapterContent = $this->replaceHtmlLinksWithRoutes($chapterContent, $book);
        
        // Sanitize content to prevent XSS (even though it's from trusted files)
        // Use Laravel's built-in e() helper for basic sanitization
        // Note: We keep HTML but ensure it's properly encoded where needed
        $chapterContent = $this->sanitizeHtmlContent($chapterContent);

        return view('student.books.read', compact(
            'book',
            'chapter',
            'chapterContent',
            'allChapters',
            'previousChapter',
            'nextChapter',
            'notes',
            'bookmarks',
            'progress'
        ));
    }

    /**
     * Show practice exercises for a chapter.
     */
    public function showPractice(Book $book, BookChapter $chapter)
    {
        // Verify chapter belongs to book
        if ($chapter->book_id !== $book->id) {
            abort(404);
        }

        // First, try to get practices from database
        $dbPractices = $chapter->practices()->where('is_active', true)->orderBy('order')->get();
        
        // If no database practices, extract from chapter content
        if ($dbPractices->isEmpty()) {
            $practicesCollection = $this->extractPracticesFromChapter($book, $chapter);
        } else {
            // Use database practices directly (they're already models)
            $practicesCollection = $dbPractices;
        }

        $practicesCount = is_countable($practicesCollection) ? count($practicesCollection) : $practicesCollection->count();

        return view('student.books.practice', compact(
            'book',
            'chapter',
            'practicesCollection',
            'practicesCount'
        ));
    }

    /**
     * Extract practice exercises from chapter HTML content.
     */
    private function extractPracticesFromChapter(Book $book, BookChapter $chapter)
    {
        $practices = [];
        
        // Read the chapter HTML file
        $filePath = public_path($book->folder_path . '/' . $chapter->file_name);
        
        if (!File::exists($filePath)) {
            return collect($practices);
        }

        $htmlContent = File::get($filePath);
        
        // Parse HTML to extract practices
        $dom = new \DOMDocument();
        @$dom->loadHTML(mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'));
        
        $xpath = new \DOMXPath($dom);
        
        // Find all subsection titles (h3 with class "subsection-title")
        $subsectionTitles = $xpath->query('//h3[@class="subsection-title"]');
        
        foreach ($subsectionTitles as $titleNode) {
            $title = trim($titleNode->textContent);
            
            // Skip certain titles that aren't practice exercises
            $skipTitles = ['Examples', 'Pattern', 'Key Points', 'Best Practices', 'Important Notes', 'Note'];
            if (in_array($title, $skipTitles)) {
                continue;
            }
            
            // Get the next code example after this subsection title
            $codeExample = null;
            $description = '';
            
            // Get description from the paragraph right after the title
            $current = $titleNode->nextSibling;
            $foundNextSubsection = false;
            
            while ($current && !$foundNextSubsection) {
                if ($current->nodeType === XML_ELEMENT_NODE) {
                    // Get description from first paragraph
                    if ($current->tagName === 'p' && !$description) {
                        $description = trim($current->textContent);
                    }
                    
                    // Check for code example
                    if ($current->tagName === 'pre' && $current->getAttribute('class') === 'code-example') {
                        $codeNode = $current->getElementsByTagName('code')->item(0);
                        if ($codeNode) {
                            $codeExample = trim($codeNode->textContent);
                        }
                    }
                    
                    // Stop if we hit next subsection
                    if ($current->tagName === 'h3' && $current->getAttribute('class') === 'subsection-title') {
                        $foundNextSubsection = true;
                        break;
                    }
                }
                $current = $current->nextSibling;
            }
            
            // If no code found in direct siblings, get first following code example
            // but only if it's before the next subsection
            if (!$codeExample) {
                $followingCodeExamples = $xpath->query('.//following::pre[@class="code-example"]', $titleNode);
                $nextSubsection = $xpath->query('.//following::h3[@class="subsection-title"]', $titleNode);
                
                if ($followingCodeExamples->length > 0) {
                    $firstCode = $followingCodeExamples->item(0);
                    
                    // If there's a next subsection, try to verify code comes before it
                    // Otherwise just use the first code we find
                    if ($nextSubsection->length === 0 || $followingCodeExamples->length === 1) {
                        // No next subsection or only one code, use it
                        $codeNode = $firstCode->getElementsByTagName('code')->item(0);
                        if ($codeNode) {
                            $codeExample = trim($codeNode->textContent);
                        }
                    } else {
                        // Multiple codes and next subsection exists - use first one
                        // (it's likely the one for this subsection)
                        $codeNode = $firstCode->getElementsByTagName('code')->item(0);
                        if ($codeNode) {
                            $codeExample = trim($codeNode->textContent);
                        }
                    }
                }
            }
            
            // Only add if we have a code example
            if ($codeExample) {
                // Determine type based on code content
                $type = 'dart';
                if (strpos($codeExample, 'import \'package:flutter') !== false || 
                    strpos($codeExample, 'runApp') !== false ||
                    strpos($codeExample, 'MaterialApp') !== false ||
                    strpos($codeExample, 'Widget') !== false) {
                    $type = 'flutter';
                }
                
                $practices[] = [
                    'id' => count($practices) + 1,
                    'title' => $title,
                    'description' => $description,
                    'code' => $codeExample,
                    'type' => $type,
                    'instructions' => 'Watch the code example above and retype it in the DartPad editor on the right. Then run it to see the results.',
                ];
            }
        }
        
        return collect($practices);
    }

    /**
     * Download chapter as PDF.
     */
    public function downloadChapter(Book $book, BookChapter $chapter)
    {
        // Verify chapter belongs to book
        if ($chapter->book_id !== $book->id) {
            abort(404);
        }

        // Check if student has outstanding balance
        $student = Auth::user();
        if ($student->role === 'student') {
            $outstandingBalance = $this->calculateOutstandingBalance($student->id);
            
            if ($outstandingBalance > 0) {
                // Check if request is AJAX/JSON
                if (request()->ajax() || request()->expectsJson() || request()->wantsJson()) {
                    return response()->json([
                        'success' => false,
                        'has_balance' => true,
                        'outstanding_balance' => $outstandingBalance,
                        'message' => 'You have an outstanding balance. Please settle your payment to download resources.',
                    ], 403);
                }
                
                // For regular requests, redirect with error
                return redirect()->back()->with('error', 'You have an outstanding balance of ₵' . number_format($outstandingBalance, 2) . '. Please settle your payment to download resources.');
            }
        }

        // Read the chapter HTML file
        $filePath = public_path($book->folder_path . '/' . $chapter->file_name);
        
        if (!File::exists($filePath)) {
            abort(404, 'Chapter file not found');
        }

        $htmlContent = File::get($filePath);
        
        // Extract only the body content
        $dom = new \DOMDocument();
        @$dom->loadHTML(mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'));
        
        $xpath = new \DOMXPath($dom);
        $container = $xpath->query('//div[@class="chapter-container"]')->item(0);
        
        if ($container) {
            $chapterContent = '';
            foreach ($container->childNodes as $node) {
                $chapterContent .= $dom->saveHTML($node);
            }
        } else {
            $body = $dom->getElementsByTagName('body')->item(0);
            if ($body) {
                $chapterContent = '';
                foreach ($body->childNodes as $node) {
                    $chapterContent .= $dom->saveHTML($node);
                }
            } else {
                $chapterContent = $htmlContent;
            }
        }

        // Generate PDF
        try {
            // Use the PDF facade (now properly registered)
            $pdf = \Barryvdh\DomPDF\Facade\Pdf::loadView('student.books.pdf', [
                'book' => $book,
                'chapter' => $chapter,
                'chapterContent' => $chapterContent,
            ]);
            
            // Generate filename
            $fileName = $book->title . ' - ' . $chapter->title . '.pdf';
            $fileName = preg_replace('/[^A-Za-z0-9\-_\.]/', '_', $fileName);
            
            return $pdf->download($fileName);
            
        } catch (\Exception $e) {
            return redirect()->back()->with('error', 'PDF generation failed: ' . $e->getMessage());
        }
    }

    /**
     * Calculate outstanding balance for a student.
     */
    private function calculateOutstandingBalance($studentId)
    {
        $enrollments = Enrollment::where('student_id', $studentId)
            ->with('course')
            ->get();
        
        $totalOutstanding = 0;
        
        foreach ($enrollments as $enrollment) {
            if ($enrollment->course) {
                $courseFee = $enrollment->course->fees;
                $paidAmount = FeePayment::where('student_id', $studentId)
                    ->where(function($q) use ($enrollment) {
                        $q->where('course_id', $enrollment->course_id);
                        if ($enrollment->course_offering_id) {
                            $q->orWhere('course_offering_id', $enrollment->course_offering_id);
                        }
                    })
                    ->sum('amount');
                
                $balance = $courseFee - $paidAmount;
                
                if ($balance > 0) {
                    $totalOutstanding += $balance;
                }
            }
        }
        
        return $totalOutstanding;
    }

    /**
     * Save a note.
     */
    public function saveNote(Request $request, Book $book, BookChapter $chapter)
    {
        $request->validate([
            'content' => 'required|string',
            'highlighted_text' => 'nullable|string',
            'position' => 'nullable|integer',
        ]);

        $note = BookNote::create([
            'user_id' => Auth::id(),
            'book_id' => $book->id,
            'book_chapter_id' => $chapter->id,
            'content' => $request->content,
            'highlighted_text' => $request->highlighted_text,
            'position' => $request->position ?? 0,
        ]);

        return response()->json([
            'success' => true,
            'note' => $note->load('chapter'),
        ]);
    }

    /**
     * Update a note.
     */
    public function updateNote(Request $request, BookNote $note)
    {
        // Verify note belongs to user
        if ($note->user_id !== Auth::id()) {
            abort(403);
        }

        $request->validate([
            'content' => 'required|string',
        ]);

        $note->update([
            'content' => $request->content,
        ]);

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

    /**
     * Delete a note.
     */
    public function deleteNote(BookNote $note)
    {
        // Verify note belongs to user
        if ($note->user_id !== Auth::id()) {
            abort(403);
        }

        $note->delete();

        return response()->json(['success' => true]);
    }

    /**
     * Save progress.
     */
    public function saveProgress(Request $request, Book $book, BookChapter $chapter)
    {
        $request->validate([
            'position' => 'required|integer',
            'is_completed' => 'nullable|boolean',
        ]);

        $progress = BookProgress::updateOrCreate(
            [
                'user_id' => Auth::id(),
                'book_id' => $book->id,
                'book_chapter_id' => $chapter->id,
            ],
            [
                'last_page_position' => $request->position,
                'is_completed' => $request->is_completed ?? false,
                'last_read_at' => now(),
            ]
        );

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

    /**
     * Create a bookmark.
     */
    public function createBookmark(Request $request, Book $book, BookChapter $chapter)
    {
        $request->validate([
            'title' => 'nullable|string|max:255',
            'note' => 'nullable|string',
            'position' => 'required|integer',
        ]);

        $bookmark = Bookmark::create([
            'user_id' => Auth::id(),
            'book_id' => $book->id,
            'book_chapter_id' => $chapter->id,
            'title' => $request->title ?? 'Bookmark',
            'note' => $request->note,
            'position' => $request->position,
        ]);

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

    /**
     * Delete a bookmark.
     */
    public function deleteBookmark(Bookmark $bookmark)
    {
        // Verify bookmark belongs to user
        if ($bookmark->user_id !== Auth::id()) {
            abort(403);
        }

        $bookmark->delete();

        return response()->json(['success' => true]);
    }

    /**
     * Get user notes for a book.
     */
    public function getNotes(Book $book)
    {
        $notes = BookNote::where('user_id', Auth::id())
            ->where('book_id', $book->id)
            ->with('chapter')
            ->orderBy('created_at', 'desc')
            ->get();

        return response()->json(['notes' => $notes]);
    }

    /**
     * Replace HTML file links in content with Laravel routes.
     */
    private function replaceHtmlLinksWithRoutes($htmlContent, $book)
    {
        // Create a mapping of file names to chapter IDs
        $chapters = $book->chapters;
        $fileToChapterMap = [];
        
        foreach ($chapters as $ch) {
            $fileToChapterMap[$ch->file_name] = $ch->id;
        }

        // Use DOMDocument to find and replace links
        // Wrap content in a temporary container for proper parsing
        $wrappedContent = '<div id="temp-container">' . $htmlContent . '</div>';
        $dom = new \DOMDocument();
        @$dom->loadHTML(mb_convert_encoding($wrappedContent, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        
        $xpath = new \DOMXPath($dom);
        
        // Find all anchor tags with href attributes
        $links = $xpath->query('//a[@href]');
        
        foreach ($links as $link) {
            $href = $link->getAttribute('href');
            
            // Check if it's a link to an HTML file (relative path)
            // Match patterns like: chapter-1.html, introduction.html, etc.
            if (preg_match('/^([^\/]+\.html)(?:#.*)?$/', $href, $matches)) {
                $fileName = $matches[1];
                
                // Check if we have a chapter for this file
                if (isset($fileToChapterMap[$fileName])) {
                    $chapterId = $fileToChapterMap[$fileName];
                    // Replace with Laravel route
                    $newHref = route('student.books.chapters.read', [
                        'book' => $book->id,
                        'chapter' => $chapterId
                    ]);
                    $link->setAttribute('href', $newHref);
                }
            }
        }
        
        // Extract content from the temporary container
        $container = $xpath->query('//div[@id="temp-container"]')->item(0);
        if ($container) {
            $updatedContent = '';
            foreach ($container->childNodes as $node) {
                $updatedContent .= $dom->saveHTML($node);
            }
            return $updatedContent;
        }
        
        // Fallback: return original content
        return $htmlContent;
    }
    
    /**
     * Sanitize HTML content to prevent XSS attacks
     * 
     * @param string $content
     * @return string
     */
    private function sanitizeHtmlContent($content)
    {
        // Use DOMDocument to parse and clean HTML
        $dom = new \DOMDocument();
        @$dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
        
        // Remove potentially dangerous elements and attributes
        $xpath = new \DOMXPath($dom);
        
        // Remove script tags
        $scripts = $xpath->query('//script');
        foreach ($scripts as $script) {
            $script->parentNode->removeChild($script);
        }
        
        // Remove event handlers from all elements
        $allElements = $xpath->query('//*');
        foreach ($allElements as $element) {
            // Remove event handler attributes
            $attributes = $element->attributes;
            if ($attributes) {
                $toRemove = [];
                foreach ($attributes as $attr) {
                    // Remove onclick, onerror, etc.
                    if (preg_match('/^on/i', $attr->name)) {
                        $toRemove[] = $attr->name;
                    }
                    // Remove javascript: protocol from href/src
                    if (in_array($attr->name, ['href', 'src', 'action']) && 
                        preg_match('/^javascript:/i', $attr->value)) {
                        $toRemove[] = $attr->name;
                    }
                }
                foreach ($toRemove as $attrName) {
                    $element->removeAttribute($attrName);
                }
            }
        }
        
        // Get cleaned HTML
        $cleaned = $dom->saveHTML();
        
        // Remove DOCTYPE and html/body tags that DOMDocument adds
        $cleaned = preg_replace('/^<!DOCTYPE.+?>/', '', $cleaned);
        $cleaned = preg_replace('/<html><body>/', '', $cleaned);
        $cleaned = preg_replace('/<\/body><\/html>$/', '', $cleaned);
        
        return trim($cleaned);
    }
}
