<?php

namespace App\Http\Controllers\Web;

use SelfPhp\SP; 
use SelfPhp\Auth;
use SelfPhp\Request;
use SelfPhp\DB\Serve;
use SelfPhp\SPException;
use SP\DataTables\SPDataTable;
use App\Http\Utils\AuthUtil;
use App\Http\Utils\DictionaryUtil;
use App\Http\Middleware\AuthMiddleware;

/**
 * Class DictionaryController
 * Handles actions related to the home page, such as rendering the home view.
 */
class DictionaryController extends SP
{
    public $authUtil;

    public $dictionaryUtil;

    /**
     * DictionaryController constructor.
     * Constructor method (currently empty).
     */
    public function __construct(AuthUtil $authUtil, DictionaryUtil $dictionaryUtil)
    { 
        $this->authUtil = $authUtil;
        $this->dictionaryUtil = $dictionaryUtil;
    }

    public function index(Request $request)
    {
        if ($request->isAjax()) {
            try {
                $datatable = new SPDataTable();
                $input = $request->captureAll();

                $words = $this->dictionaryUtil->getAllWords($input, true);

                $output = $datatable->setTableData($words)
                    ->setCustomContent('word', function ($row) {
                        $html  = '<strong>' . htmlspecialchars($row['original_word']) . '</strong>';

                        if (!empty($row['ipaWord'])) {
                            $html .= '<div class="text-muted small">/' . htmlspecialchars($row['ipaWord']) . '/</div>';
                        } else {
                            $row['ipaWord'] = $this->authUtil->toIPA($row['original_word']);
                            $html .= '<div class="text-muted small">/' . htmlspecialchars($row['ipaWord']) . '/</div>';
                        }

                        return $html;
                    })
                    ->setCustomContent('meaning', function ($row) {
                        return '
                            <div class="text-truncate" style="max-width: 250px;">
                                <div><strong>English Meaning:</strong> ' . htmlspecialchars(!empty($row['original_meaning']) ? $row['original_meaning'] : "N/A") . '</div>
                            </div>
                        ';
                    })
                    ->setCustomContent('pronunciation', function ($row) {
                        if (empty($row['pronunciation'])) {
                            return '<span class="badge bg-info">Pronunciation N/A</span>';
                        }

                        return '
                            <button class="btn btn-sm btn-outline-primary play-audio"
                                data-audio="' . storage_path('uploads/pronunciations/' . $row['pronunciation']) . '">
                                <i class="bi bi-volume-up"></i>
                            </button>
                        ';
                    })
                    ->setCustomContent('category_name', function ($row) {
                        return '<span class="badge bg-info">'
                            . htmlspecialchars($row['category_name'] ?? 'Uncategorized')
                            . '</span>';
                    })
                    ->setCustomContent('word_type_name', function ($row) {
                        return htmlspecialchars($row['word_type_name'] ?? 'N/A');
                    })
                    ->setCustomContent('status', function ($row) {
                        $status = strtolower($row['status'] ?? 'draft');

                        $class = match ($status) {
                            'published' => 'bg-success',
                            'archived'  => 'bg-secondary',
                            default     => 'bg-warning'
                        };

                        return '<span class="badge ' . $class . '">' . ucfirst($status) . '</span>';
                    })
                    ->setCustomContent('created_at', function ($row) {
                        return date('Y-m-d', strtotime($row['created_at']));
                    })
                    ->setCustomContent('actions', function ($row) {
                        return '
                            <div class="btn-group action-btns" role="group">
                                <button type="button" class="btn btn-sm btn-outline-primary word-action-btn edit"
                                    target-modal="#updateWordModal" data-id="' . $row['id'] . '" title="Edit">
                                    <i class="bi bi-pencil"></i>
                                </button>
                                <button type="button" class="btn btn-sm btn-outline-info word-action-btn view"
                                    target-modal="#viewWordModal" data-id="' . $row['id'] . '" title="View">
                                    <i class="bi bi-eye"></i>
                                </button>
                                <button type="button" class="btn btn-sm btn-outline-danger word-action-btn delete"
                                    data-id="' . $row['id'] . '" title="Delete">
                                    <i class="bi bi-trash"></i>
                                </button>
                            </div>
                        ';
                    })
                    ->removeColumn('id')
                    ->removeColumn('updated_at')
                    ->removeColumn('deleted_at')
                    ->removeColumn('deleted_by')
                    ->make();

                return [
                    'status' => 'success',
                    'data'   => $output
                ];
            } catch (SPException $th) {
                return [
                    'status'  => 'error',
                    'message' => $th->getMessage()
                ];
            } catch (\Throwable $th) { 
                return [
                    'status'  => 'error',
                    'message' => 'Unexpected error occurred. Please contact system administrator.'
                ];
            }
        }

        return view('views.dictionary.words');
    }

    public function wordsList(Request $request)
    {
        if ($request->isAjax()) {
            try {
                $datatable = new SPDataTable();
                $input = $request->captureAll();

                $words = $this->dictionaryUtil->getAllWords($input, true);

                $output = $datatable->setTableData($words)
                    ->setCustomContent('word', function ($row) {
                        $html  = '<strong>' . htmlspecialchars($row['original_word']) . '</strong>';

                        if (!empty($row['ipaWord'])) {
                            $html .= '<div class="text-muted small">/' . htmlspecialchars($row['ipaWord']) . '/</div>';
                        } else {
                            $row['ipaWord'] = $this->authUtil->toIPA($row['original_word']);
                            $html .= '<div class="text-muted small">/' . htmlspecialchars($row['ipaWord']) . '/</div>';
                        }

                        return $html;
                    })
                    ->setCustomContent('meaning', function ($row) {
                        return '
                            <div class="text-truncate" style="max-width: 250px;">
                                <div><strong>English Meaning:</strong> ' . htmlspecialchars(!empty($row['original_meaning']) ? $row['original_meaning'] : "N/A") . '</div>
                            </div>
                        ';
                    })
                    ->setCustomContent('pronunciation', function ($row) {
                        if (empty($row['pronunciation'])) {
                            return '<span class="badge bg-info">Pronunciation N/A</span>';
                        }

                        return '
                            <button class="btn btn-sm btn-outline-primary play-audio"
                                data-audio="' . storage_path('uploads/pronunciations/' . $row['pronunciation']) . '">
                                <i class="bi bi-volume-up"></i>
                            </button>
                        ';
                    })
                    ->setCustomContent('category_name', function ($row) {
                        return '<span class="badge bg-info">'
                            . htmlspecialchars($row['category_name'] ?? 'Uncategorized')
                            . '</span>';
                    })
                    ->setCustomContent('word_type_name', function ($row) {
                        return htmlspecialchars($row['word_type_name'] ?? 'N/A');
                    })
                    ->setCustomContent('status', function ($row) {
                        $status = strtolower($row['status'] ?? 'draft');

                        $class = match ($status) {
                            'published' => 'bg-success',
                            'archived'  => 'bg-secondary',
                            default     => 'bg-warning'
                        };

                        return '<span class="badge ' . $class . '">' . ucfirst($status) . '</span>';
                    })
                    ->setCustomContent('created_at', function ($row) {
                        return date('Y-m-d', strtotime($row['created_at']));
                    })
                    ->setCustomContent('actions', function ($row) {
                        return '
                            <div class="btn-group action-btns" role="group">
                                <button type="button" class="btn btn-sm btn-outline-primary word-action-btn edit"
                                    target-modal="#updateWordModal" data-id="' . $row['id'] . '" title="Edit">
                                    <i class="bi bi-pencil"></i>
                                </button>
                                <button type="button" class="btn btn-sm btn-outline-info word-action-btn view"
                                    target-modal="#viewWordModal" data-id="' . $row['id'] . '" title="View">
                                    <i class="bi bi-eye"></i>
                                </button>
                                <button type="button" class="btn btn-sm btn-outline-danger word-action-btn delete"
                                    data-id="' . $row['id'] . '" title="Delete">
                                    <i class="bi bi-trash"></i>
                                </button>
                            </div>
                        ';
                    })
                    ->removeColumn('id')
                    ->removeColumn('updated_at')
                    ->removeColumn('deleted_at')
                    ->removeColumn('deleted_by')
                    ->make();

                return [
                    'status' => 'success',
                    'data'   => $output
                ];
            } catch (SPException $th) {
                return [
                    'status'  => 'error',
                    'message' => $th->getMessage()
                ];
            } catch (\Throwable $th) {
                print_r($th->getMessage());
                return [
                    'status'  => 'error',
                    'message' => 'Unexpected error occurred. Please contact system administrator.'
                ];
            }
        }

        return view('views.dictionary.words');
    }

    public function categories(Request $request)
    {
        if ($request->isAjax()) {
            try {
                $datatable = new SPDataTable();
                $input = $request->captureAll();
                $categories = $this->dictionaryUtil->getAllCategories($input, true);
                $output = $datatable->setTableData($categories)
                    ->setCustomContent('actions', function ($row) {
                        $btn = '<button type="button" class="btn btn-sm btn-primary category-action-btn float-end me-1 edit" target-modal="#editCategoryModal" data-id="' . $row['id'] . '">Edit</button>';
                        $btn .= '<button type="button" class="btn btn-sm btn-danger category-action-btn float-end me-1 delete" data-id="' . $row['id'] . '">Delete</button>';

                        return '<div class="action-btns">' . $btn . '</div>';
                    })
                    ->setCustomContent('status', function ($row) {
                        return '<span class="badge bg-success">' . ucwords($row['status']) . '</span>';
                    })
                    ->setCustomContent('created_at', function ($row) {
                        $created_at = dateTimeFormat($row['created_at'], 'd M, Y h:i A');
                        return $created_at ? $created_at : 'N/A';
                    })
                    ->removeColumn('updated_at')
                    ->removeColumn('deleted_at')
                    ->removeColumn('id')
                    ->make();

                return ['status' => 'success', 'data' => $output];
            } catch (SPException $th) {
                return ['status' => 'error', 'message' => $th->getMessage()];
            } catch (\Throwable $th) {
                return ['status' => 'error', 'message' => "Unexpected error occurred. Please contact system administrator."];
            }
        }

        return view("views.dictionary.category");
    }

    public function createCategory(Request $request)
    {
        try {
            $input = $request->captureAll();
            if (isset($input['modal']) && !empty($input['modal'])) {
                return view("views.dictionary.partials.create-category");
            }

            if (!isset($input['name']) || empty(trim($input['name']))) {
                throw new SPException("Category name is required.");
            }

            if (!isset($input['slug']) || empty(trim($input['slug']))) {
                throw new SPException("Category slug is required.");
            }

            if (isset($input['has_parent_category']) && $input['has_parent_category'] === 'on') {
                if (!isset($input['parent_id']) || empty(trim($input['parent_id']))) {
                    throw new SPException("Parent category is required for sub-categories.");
                }
            }

            $save = $this->dictionaryUtil->createCategory($input);
            if (!$save) {
                throw new SPException("Failed to create category. Please try again.");
            }

            return [
                'status' => 'success',
                'message' => 'Category created successfully.'
            ];
        } catch (SPException $th) {
            return [
                'status' => 'error',
                'message' => $th->getMessage()
            ];
        } catch (\Throwable $th) {
            return [
                'status' => 'error',
                'message' => "Unexpected error occurred. Please contact system administrator."
            ];
        }
    }

    public function updateCategory(Request $request)
    {
        try {
            $input = $request->captureAll();
            if (isset($input['modal']) && !empty($input['modal'])) {
                $category = $this->dictionaryUtil->getCategoryById($input['categoryId']);
                $categories = $this->dictionaryUtil->getAllCategories([], true);
                return view(
                    "views.dictionary.partials.update-category",
                    compact('category', 'categories')
                );
            }

            if (!isset($input['name']) || empty(trim($input['name']))) {
                throw new SPException("Category name is required.");
            }

            if (!isset($input['slug']) || empty(trim($input['slug']))) {
                throw new SPException("Category slug is required.");
            }

            if (isset($input['has_parent_category']) && $input['has_parent_category'] === 'on') {
                if (!isset($input['parent_id']) || empty(trim($input['parent_id']))) {
                    throw new SPException("Parent category is required for sub-categories.");
                }
            }

            $save = $this->dictionaryUtil->updateCategoryUtil($input);
            if (!$save) {
                throw new SPException("Failed to update category. Please try again.");
            }

            return [
                'status' => 'success',
                'message' => 'Category updated successfully.'
            ];
        } catch (SPException $th) {
            return [
                'status' => 'error',
                'message' => $th->getMessage()
            ];
        } catch (\Throwable $th) {
            return [
                'status' => 'error',
                'message' => "Unexpected error occurred. Please contact system administrator."
            ];
        }
    }

    public function deleteCategory(Request $request)
    {
        try {
            $input = $request->captureAll();
            if (!isset($input['categoryId']) || empty(trim($input['categoryId']))) {
                throw new SPException("An authorization error ocurred. Please try again!");
            }

            $delete = $this->dictionaryUtil->deleteCategoryUtil($input);
            if (!$delete) {
                throw new SPException("Failed to delete category. Please try again.");
            }

            return [
                'status' => 'success',
                'message' => 'Category deleted successfully.'
            ];
        } catch (SPException $th) {
            return [
                'status' => 'error',
                'message' => $th->getMessage()
            ];
        } catch (\Throwable $th) {
            return [
                'status' => 'error',
                'message' => "Unexpected error occurred. Please contact system administrator."
            ];
        }
    }

    private function languages()
    {
        $languages = $this->dictionaryUtil->getAllLanguages([], true);
        return $languages;
    }

    private function wordCategories()
    {
        $categories = $this->dictionaryUtil->getAllCategories([], true);
        return $categories;
    }

    private function wordTypes()
    {
        $wordTypes = $this->dictionaryUtil->getAllWordTypes([], true);
        return $wordTypes;
    }

    public function createWord(Request $request)
    {
        Serve::beginTransaction();

        try {
            $input = $request->captureAll();

            // ORIGINAL WORD
            if (isset($input['modal']) && !empty($input['modal'])) {
                $categories = $this->wordCategories();
                $wordTypes = $this->wordTypes();
                $languages = $this->languages();
                return view(
                    "views.dictionary.partials.create-word",
                    compact('categories', 'wordTypes', 'languages')
                );
            }

            // Validate required fields one by one,
            if (!isset($input['category_id']) || empty(trim($input['category_id']))) {
                throw new SPException("Category is required.");
            }

            if (!isset($input['original_word']) || empty(trim($input['original_word']))) {
                throw new SPException("Word is required.");
            }

            if (!isset($input['word_type_id']) || empty(trim($input['word_type_id']))) {
                throw new SPException("Word type is required.");
            }

            if (!isset($input['original_meaning']) || empty(trim($input['original_meaning']))) {
                throw new SPException("Meaning is required.");
            }

            $input['word_image'] = null;
            $input['pronunciation'] = null;
            $word_image = $request->file('word_image');
            $pronunciation = $request->file('pronunciation');

            if (!empty($word_image)) {
                $input['word_image'] = $request->moveFile('word_image', 'public/storage/uploads/words/images', 'word_image_' . $input['original_word']);
                $fileInfo = pathinfo(basename($filePath));
                $input['word_image'] = $fileInfo['basename'];
            }

            if (!empty($pronunciation)) {
                $input['pronunciation'] = $request->moveFile('pronunciation', 'public/storage/uploads/words/pronunciations', 'pronunciation_' . $input['original_word']);
                $fileInfo = pathinfo(basename($filePath));
                $input['pronunciation'] = $fileInfo['basename'];
            }

            // TRANSLATION OF WORD (OPTIONAL If Data is not found, skip)
            if (!empty($input['translation_language']) && !empty($input['translated_word']) && !empty($input['translated_meaning'])) {
                $input['trans_word_image'] = null;
                $input['trans_pronunciation'] = null;
                $word_image = $request->file('trans_word_image');
                $pronunciation = $request->file('trans_pronunciation');

                if (!empty($word_image)) {
                    $filePath = $request->moveFile('trans_word_image', 'public/storage/uploads/words/images', 'word_image_' . $input['translated_word']);
                    $fileInfo = pathinfo(basename($filePath));
                    $input['trans_word_image'] = $fileInfo['basename'];
                }

                if (!empty($pronunciation)) {
                    $filePath = $request->moveFile('trans_pronunciation', 'public/storage/uploads/words/pronunciations', 'pronunciation_' . $input['translated_word']);
                    $fileInfo = pathinfo(basename($filePath));
                    $input['trans_pronunciation'] = $fileInfo['basename'];
                }
            }

            $save = $this->dictionaryUtil->createWord($input);
            if (!$save) {
                throw new SPException("Failed to create word. Please try again.");
            }

            Serve::commit();
            return [
                'status' => 'success',
                'message' => 'Word created successfully.'
            ];
        } catch (SPException $th) {
            Serve::rollback();
            return [
                'status' => 'error',
                'message' => $th->getMessage()
            ];
        } catch (\Throwable $th) {
            Serve::rollback(); 
            DEBUG($th->getMessage());
            return [
                'status' => 'error',
                'message' => "Unexpected error occurred. Please contact system administrator."
            ];
        }
    }

    public function updateWord(Request $request)
    {
        Serve::beginTransaction();
        
        try {
            $input = $request->captureAll();

            if (isset($input['wordId']) && empty(trim($input['wordId']))) {
                throw new SPException("An authorization error ocurred. Please try again!");
            }

            $word = $this->dictionaryUtil->getWordById($input['wordId'], true);
            if (empty($word)) {
                throw new SPException("Word not found. Please try again.");
            }

            if (isset($input['modal']) && !empty($input['modal'])) {
                $wordTypes = $this->wordTypes();
                $categories = $this->wordCategories();
                $languages = $this->languages();
                $translation = $this->dictionaryUtil->getWordTranslationByWordId($word['id'], true); 
                $word['word_image'] = storage_path('uploads/words/images/' . $word['word_image'] ?? null);
                $word['pronunciation'] = isset($word['pronunciation']) ? storage_path('uploads/words/pronunciations/' . $word['pronunciation']) : null;
                $translation['trans_word_image'] = isset($translation['trans_word_image']) ? storage_path('uploads/words/images/' . $translation['trans_word_image']) : null;
                $translation['trans_pronunciation'] = isset($translation['trans_pronunciation']) ? storage_path('uploads/words/pronunciations/' . $translation['trans_pronunciation']) : null;
                return view(
                    "views.dictionary.partials.update-word",
                    compact('word', 'languages', 'categories', 'wordTypes', 'translation')
                );
            }

            // Validate required fields one by one,
            if (!isset($input['category_id']) || empty(trim($input['category_id']))) {
                throw new SPException("Category is required.");
            }

            if (!isset($input['word_type_id']) || empty(trim($input['word_type_id']))) {
                throw new SPException("Word type is required.");
            }

            if (!isset($input['original_word']) || empty(trim($input['original_word']))) {
                throw new SPException("Word is required.");
            }

            if (!isset($input['original_meaning']) || empty(trim($input['original_meaning']))) {
                throw new SPException("Meaning is required.");
            }

            $input['word_image'] = $word['word_image'] ?? null;
            $input['pronunciation'] = $word['pronunciation'] ?? null;
            $word_image = $request->file('word_image');
            $pronunciation = $request->file('pronunciation');

            if (!empty($word_image)) {
                $filePath = $request->moveFile('word_image', 'public/storage/uploads/words/images', 'word_image_' . $input['original_word']);
                $fileInfo = pathinfo(basename($filePath));
                $input['word_image'] = $fileInfo['basename'];
            }

            if (!empty($pronunciation)) {
                $filePath = $request->moveFile('pronunciation', 'public/storage/uploads/words/pronunciations', 'pronunciation_' . $input['original_word']);
                $fileInfo = pathinfo(basename($filePath));
                $input['pronunciation'] = $fileInfo['basename'];
            }

            // TRANSLATION OF WORD (OPTIONAL If Data is not found, skip)
            if (!empty($input['translation_language']) && !empty($input['translated_word']) && !empty($input['translated_meaning'])) {
                $input['trans_word_image'] = null;
                $input['trans_pronunciation'] = null;
                $word_image = $request->file('trans_word_image');
                $pronunciation = $request->file('trans_pronunciation');

                if (!empty($word_image)) {
                    $filePath = $request->moveFile('trans_word_image', 'public/storage/uploads/words/images', 'word_image_' . $input['translated_word']);
                    $fileInfo = pathinfo(basename($filePath));
                    $input['trans_word_image'] = $fileInfo['basename'];
                }

                if (!empty($pronunciation)) {
                    $filePath = $request->moveFile('trans_pronunciation', 'public/storage/uploads/words/pronunciations', 'pronunciation_' . $input['translated_word']);
                    $fileInfo = pathinfo(basename($filePath));
                    $input['trans_pronunciation'] = $fileInfo['basename'];
                }
            }

            $save = $this->dictionaryUtil->updateWordUtil($input);
            if (!$save) {
                throw new SPException("Failed to update word. Please try again.");
            }

            // Delete the previous image/pronunciation if new one is uploaded
            if (!empty($word_image) && !empty($word['word_image'])) {
                $request->deleteFile('public/storage/uploads/words/images/' . $word['word_image']);
            }

            if (!empty($pronunciation) && !empty($word['pronunciation'])) {
                $request->deleteFile('public/storage/uploads/words/pronunciations/' . $word['pronunciation']);
            }


            Serve::commit();
            return [
                'status' => 'success',
                'message' => 'Word updated successfully.'
            ];
        } catch (SPException $th) {
            Serve::rollback();
            return [
                'status' => 'error',
                'message' => $th->getMessage()
            ];
        } catch (\Throwable $th) {
            Serve::rollback(); 
            return [
                'status' => 'error',
                'message' => "Unexpected error occurred. Please contact system administrator."
            ];
        }
    }

    public function showWord(Request $request)
    { 
        try {
            $input = $request->captureAll();
            
            if (isset($input['wordId']) && empty(trim($input['wordId']))) {
                throw new SPException("An authorization error ocurred. Please try again!");
            }

            $word = $this->dictionaryUtil->getDetailedWordById($input['wordId'], true);
            if (empty($word)) {
                throw new SPException("Word not found. Please try again.");
            }

            return view("views.dictionary.show", compact('word'));
        } catch (SPException $th) { 
            return [
                'status' => 'error',
                'message' => $th->getMessage()
            ];
        } catch (\Throwable $th) { 
            DEBUG($th->getMessage());
            return [
                'status' => 'error',
                'message' => "Unexpected error occurred. Please contact system administrator."
            ];
        }
    }

    public function deleteWord(Request $request)
    {
        // ...
    }
}
