<?php

namespace App\Http\Controllers;

use App\Models\MeetingBook;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;

class MeetingBookController extends Controller
{
    /**
     * Get all MeetingBook records.
     */
    public function index()
    {
        $meetingBooks = MeetingBook::with(['society'])->get();

        // Format the dates to Indian Standard Time format (dd/mm/yyyy H:i:s)
        $meetingBooks->each(function ($meetingBook) {
            $meetingBook->STDate = $meetingBook->STDate ? Carbon::parse($meetingBook->STDate)->format('d/m/Y H:i:s') : null;
            $meetingBook->StTime = $meetingBook->StTime ? Carbon::parse($meetingBook->StTime)->format('d/m/Y H:i:s') : null;
            $meetingBook->EdTime = $meetingBook->EdTime ? Carbon::parse($meetingBook->EdTime)->format('d/m/Y H:i:s') : null;
            // Convert Meeting_Doc paths to full URLs
            $meetingBook->Meeting_Doc = $meetingBook->Meeting_Doc ? array_map(function ($path) {
                return url('storage/' . $path);
            }, json_decode($meetingBook->Meeting_Doc, true)) : null;
        });

        return response()->json($meetingBooks);
    }

    /**
     * Get a specific MeetingBook record by MB_Id.
     */
    public function show($id)
    {
        $meetingBook = MeetingBook::with(['society'])->find($id);

        if (!$meetingBook) {
            return response()->json(['message' => 'Record not found'], 404);
        }

        // Format the dates to Indian Standard Time format (dd/mm/yyyy H:i:s)
        $meetingBook->STDate = $meetingBook->STDate ? Carbon::parse($meetingBook->STDate)->format('d/m/Y H:i:s') : null;
        $meetingBook->StTime = $meetingBook->StTime ? Carbon::parse($meetingBook->StTime)->format('d/m/Y H:i:s') : null;
        $meetingBook->EdTime = $meetingBook->EdTime ? Carbon::parse($meetingBook->EdTime)->format('d/m/Y H:i:s') : null;
        // Convert Meeting_Doc paths to full URLs
        $meetingBook->Meeting_Doc = $meetingBook->Meeting_Doc ? array_map(function ($path) {
            return url('storage/' . $path);
        }, json_decode($meetingBook->Meeting_Doc, true)) : null;

        return response()->json($meetingBook);
    }

    /**
     * Create a new MeetingBook record.
     */
    public function store(Request $request)
    {
        // Log the incoming request data for debugging
        Log::debug('Store request data:', $request->all());

        $validator = Validator::make($request->all(), [
            'SocId'         => 'required|integer|exists:society_master,SocId',
            'Venue'         => 'nullable|string|max:25',
            'Agenda'        => 'nullable|string|max:250',
            'STDate'        => 'nullable|date_format:d/m/Y H:i:s',
            'StTime'        => 'nullable|date_format:d/m/Y H:i:s',
            'EdTime'        => 'nullable|date_format:d/m/Y H:i:s',
            'Status'        => 'nullable|string|max:1',
            'Meeting_Doc.*' => 'nullable|file|mimes:pdf,doc,docx,jpg,jpeg,png|max:20480', // Support multiple files, max 20MB
        ]);

        if ($validator->fails()) {
            Log::error('Validation failed:', $validator->errors()->toArray());
            return response()->json(['errors' => $validator->errors()], 422);
        }

        try {
            // Parse dates only if provided and not empty
            $stDate = $request->input('STDate') ? Carbon::createFromFormat('d/m/Y H:i:s', $request->input('STDate'))->format('Y-m-d H:i:s') : null;
            $stTime = $request->input('StTime') ? Carbon::createFromFormat('d/m/Y H:i:s', $request->input('StTime'))->format('Y-m-d H:i:s') : null;
            $edTime = $request->input('EdTime') ? Carbon::createFromFormat('d/m/Y H:i:s', $request->input('EdTime'))->format('Y-m-d H:i:s') : null;
        } catch (\Exception $e) {
            Log::error('Invalid date format:', ['error' => $e->getMessage()]);
            return response()->json(['errors' => 'Invalid date format. Use dd/mm/yyyy H:i:s'], 422);
        }

        // Define the base storage path
        $basePath = public_path('storage'); // Points to public/storage

        // Store files (images and PDFs) and generate relative paths
        $filePaths = [];
        if ($request->hasFile('Meeting_Doc')) {
            foreach ($request->file('Meeting_Doc') as $file) {
                $originalName = $file->getClientOriginalName();
                $extension = $file->getClientOriginalExtension();
                $filePath = 'meetings/' . $originalName;
                $destinationPath = $basePath . '/' . $filePath;

                // Check if file exists and rename with timestamp
                if (file_exists($destinationPath)) {
                    $filenameWithoutExt = pathinfo($originalName, PATHINFO_FILENAME);
                    $newFileName = $filenameWithoutExt . '_' . time() . '.' . $extension;
                    $filePath = 'meetings/' . $newFileName;
                    $destinationPath = $basePath . '/' . $filePath;
                }

                // Ensure the directory exists
                if (!file_exists(dirname($destinationPath))) {
                    mkdir(dirname($destinationPath), 0755, true);
                }

                // Move the file to the destination
                $file->move(dirname($destinationPath), basename($filePath));

                // Store relative path
                $filePaths[] = $filePath;
            }
        }

        $data = [
            'SocId'       => $request->input('SocId'),
            'Venue'       => $request->input('Venue'),
            'Agenda'      => $request->input('Agenda'),
            'STDate'      => $stDate,
            'StTime'      => $stTime,
            'EdTime'      => $edTime,
            'Status'      => $request->input('Status'),
            'Meeting_Doc' => !empty($filePaths) ? json_encode($filePaths) : null, // Store relative paths as JSON
        ];

        $meetingBook = MeetingBook::create($data);

        // Prepare response with full URLs
        $responseData = $meetingBook->toArray();
        $responseData['Meeting_Doc'] = $meetingBook->Meeting_Doc ? array_map(function ($path) {
            return url('storage/' . $path);
        }, json_decode($meetingBook->Meeting_Doc, true)) : null;

        Log::info('MeetingBook created:', $responseData);

        return response()->json($responseData, 201);
    }

    /**
     * Update a MeetingBook record by MB_Id.
     */
    public function update(Request $request, $id)
    {
        $meetingBook = MeetingBook::find($id);

        if (!$meetingBook) {
            return response()->json(['message' => 'Record not found'], 404);
        }

        // Log the incoming request data for debugging
        Log::debug('Update request data:', $request->all());
        if ($request->has('Meeting_Doc')) {
            Log::debug('Meeting_Doc input:', ['Meeting_Doc' => $request->input('Meeting_Doc')]);
        }

        // Custom validation for Base64 strings and URLs
        $validator = Validator::make($request->all(), [
            'SocId'         => 'required|integer|exists:society_master,SocId',
            'Venue'         => 'nullable|string|max:25',
            'Agenda'        => 'nullable|string|max:250',
            'STDate'        => 'nullable|date_format:d/m/Y H:i:s',
            'StTime'        => 'nullable|date_format:d/m/Y H:i:s',
            'EdTime'        => 'nullable|date_format:d/m/Y H:i:s',
            'Status'        => 'nullable|string|max:1',
            'Meeting_Doc'   => 'nullable|array',
            'Meeting_Doc.*' => [
                'nullable',
                'string',
                function ($attribute, $value, $fail) {
                    // Check if it's a URL (existing file)
                    if (preg_match('/^https?:\/\/.*\/storage\/meetings\/(.+\.(pdf|doc|docx|jpg|jpeg|png))$/i', $value)) {
                        return; // Valid URL
                    }

                    // Check if it's a Base64 string with data: prefix
                    if (preg_match('/^data:(image\/(jpeg|png|jpg)|application\/(pdf|msword|vnd\.openxmlformats-officedocument\.wordprocessingml\.document));base64,(.+)/', $value, $matches)) {
                        $base64Data = $matches[3];
                        $decodedData = base64_decode($base64Data, true);
                        if ($decodedData === false) {
                            Log::error("Base64 decoding failed for $attribute");
                            $fail("The $attribute contains invalid Base64 data.");
                            return;
                        }
                        if (strlen($decodedData) > 20480 * 1024) { // 20MB in bytes
                            Log::error("File size too large for $attribute", ['size' => strlen($decodedData)]);
                            $fail("The $attribute file size must not exceed 20480 KB.");
                        }
                        return;
                    }

                    // Check if it's a raw Base64 string
                    if (preg_match('/^[A-Za-z0-9+\/=]+$/', $value)) {
                        $decodedData = base64_decode($value, true);
                        if ($decodedData === false) {
                            Log::error("Base64 decoding failed for $attribute");
                            $fail("The $attribute contains invalid Base64 data.");
                            return;
                        }
                        if (strlen($decodedData) > 20480 * 1024) { // 20MB in bytes
                            Log::error("File size too large for $attribute", ['size' => strlen($decodedData)]);
                            $fail("The $attribute file size must not exceed 20480 KB.");
                            return;
                        }

                        // Detect MIME type for raw Base64
                        $mimeType = $this->detectMimeType($decodedData);
                        if (!$mimeType || !in_array($mimeType, [
                            'image/jpeg',
                            'image/png',
                            'image/jpg',
                            'application/pdf',
                            'application/msword',
                            'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
                        ])) {
                            Log::error("Unsupported MIME type for $attribute", ['mimeType' => $mimeType]);
                            $fail("The $attribute must be a valid file type: pdf, doc, docx, jpg, jpeg, png.");
                            return;
                        }
                        return;
                    }

                    Log::error("Invalid format for $attribute", ['value' => substr($value, 0, 100)]);
                    $fail("The $attribute must be a valid Base64 string of type: pdf, doc, docx, jpg, jpeg, png, or a valid file URL.");
                },
            ],
        ]);

        if ($validator->fails()) {
            Log::error('Validation failed:', $validator->errors()->toArray());
            return response()->json(['errors' => $validator->errors()], 422);
        }

        try {
            // Parse dates only if provided and not empty
            $stDate = $request->input('STDate') ? Carbon::createFromFormat('d/m/Y H:i:s', $request->input('STDate'))->format('Y-m-d H:i:s') : null;
            $stTime = $request->input('StTime') ? Carbon::createFromFormat('d/m/Y H:i:s', $request->input('StTime'))->format('Y-m-d H:i:s') : null;
            $edTime = $request->input('EdTime') ? Carbon::createFromFormat('d/m/Y H:i:s', $request->input('EdTime'))->format('Y-m-d H:i:s') : null;
        } catch (\Exception $e) {
            Log::error('Invalid date format:', ['error' => $e->getMessage()]);
            return response()->json(['errors' => 'Invalid date format. Use dd/mm/yyyy H:i:s'], 422);
        }

        // Define the base storage path
        $basePath = public_path('storage'); // Points to public/storage

        // Initialize file paths with existing files
        $filePaths = $meetingBook->Meeting_Doc ? json_decode($meetingBook->Meeting_Doc, true) : [];

        // Handle Meeting_Doc entries
        if ($request->has('Meeting_Doc') && is_array($request->input('Meeting_Doc'))) {
            foreach ($request->input('Meeting_Doc') as $index => $item) {
                // Handle URLs (existing files)
                if (preg_match('/^https?:\/\/.*\/storage\/meetings\/(.+\.(pdf|doc|docx|jpg|jpeg|png))$/i', $item, $matches)) {
                    $relativePath = 'meetings/' . $matches[1];
                    $filePaths[$index] = $relativePath; // Place at specific index
                    Log::info("Preserved existing file URL for Meeting_Doc[{$index}]", ['path' => $relativePath]);
                    continue;
                }

                // Handle Base64 strings (with or without data: prefix)
                $base64Data = $item;
                $extension = 'png'; // Default, will be overridden
                $mimeType = 'image/png';

                // Check if it has data: prefix
                if (preg_match('/^data:(image\/(jpeg|png|jpg)|application\/(pdf|msword|vnd\.openxmlformats-officedocument\.wordprocessingml\.document));base64,(.+)/', $item, $matches)) {
                    $mimeType = $matches[1];
                    $base64Data = $matches[3];
                } else {
                    // For raw Base64, detect MIME type from decoded data
                    $decodedData = base64_decode($item, true);
                    if ($decodedData === false) {
                        Log::error("Base64 decoding failed for Meeting_Doc[{$index}]");
                        return response()->json(['error' => "Invalid Base64 data for Meeting_Doc[{$index}]"], 422);
                    }
                    $mimeType = $this->detectMimeType($decodedData);
                    if (!$mimeType) {
                        Log::error("Could not detect MIME type for Meeting_Doc[{$index}]");
                        return response()->json(['error' => "Unsupported file type for Meeting_Doc[{$index}]"], 422);
                    }
                }

                // Get the correct extension
                $extension = $this->getExtensionFromMimeType($mimeType);

                // Decode Base64 string
                $fileData = base64_decode($base64Data, true);
                if ($fileData === false) {
                    Log::error("Base64 decoding failed for Meeting_Doc[{$index}]");
                    return response()->json(['error' => "Invalid Base64 data for Meeting_Doc[{$index}]"], 422);
                }

                // Delete old file at this index if it exists
                if (isset($filePaths[$index])) {
                    $oldFilePath = $filePaths[$index];
                    $fullOldPath = public_path('storage/' . $oldFilePath);
                    if (file_exists($fullOldPath)) {
                        unlink($fullOldPath);
                        Log::info("Deleted old file for Meeting_Doc[{$index}]", ['path' => $oldFilePath]);
                    }
                }

                // Generate a unique filename
                $fileName = time() . '-' . uniqid() . '.' . $extension;
                $filePath = 'meetings/' . $fileName;
                $destinationPath = $basePath . '/' . $filePath;

                // Ensure the directory exists
                if (!file_exists(dirname($destinationPath))) {
                    mkdir(dirname($destinationPath), 0755, true);
                }

                // Save the file
                file_put_contents($destinationPath, $fileData);
                $filePaths[$index] = $filePath; // Replace at specific index
                Log::info("Replaced file with Base64 for Meeting_Doc[{$index}]", ['path' => $filePath, 'mimeType' => $mimeType]);
            }
        }

        $data = [
            'SocId'       => $request->input('SocId'),
            'Venue'       => $request->input('Venue'),
            'Agenda'      => $request->input('Agenda'),
            'STDate'      => $stDate,
            'StTime'      => $stTime,
            'EdTime'      => $edTime,
            'Status'      => $request->input('Status'),
            'Meeting_Doc' => !empty($filePaths) ? json_encode(array_values($filePaths)) : null, // Store relative paths as JSON
        ];

        $meetingBook->update($data);

        // Prepare response with full URLs
        $responseData = $meetingBook->toArray();
        $responseData['Meeting_Doc'] = $meetingBook->Meeting_Doc ? array_map(function ($path) {
            return url('storage/' . $path);
        }, json_decode($meetingBook->Meeting_Doc, true)) : null;

        Log::info('MeetingBook updated:', $responseData);

        return response()->json($responseData);
    }

    /**
     * Detect MIME type from decoded data
     *
     * @param string $decodedData
     * @return string|null
     */
    private function detectMimeType($decodedData)
    {
        try {
            $finfo = new \finfo(FILEINFO_MIME_TYPE);
            $mimeType = $finfo->buffer($decodedData);
            return $mimeType;
        } catch (\Exception $e) {
            Log::error('MIME type detection failed:', ['error' => $e->getMessage()]);
            return null;
        }
    }

    /**
     * Get file extension from MIME type
     *
     * @param string $mimeType
     * @return string
     */
    private function getExtensionFromMimeType($mimeType)
    {
        $extensions = [
            'image/jpeg' => 'jpeg',
            'image/png' => 'png',
            'image/jpg' => 'jpg',
            'application/pdf' => 'pdf',
            'application/msword' => 'doc',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
        ];

        return $extensions[$mimeType] ?? 'bin'; // Default to .bin for unknown types
    }

    /**
     * Delete a MeetingBook record by MB_Id.
     */
    public function destroy($id)
    {
        $meetingBook = MeetingBook::find($id);

        if (!$meetingBook) {
            return response()->json(['message' => 'Record not found'], 404);
        }

        // Delete associated files if they exist
        if (!empty($meetingBook->Meeting_Doc)) {
            $files = json_decode($meetingBook->Meeting_Doc, true);
            if (is_array($files)) {
                foreach ($files as $filePath) {
                    $fullFilePath = public_path('storage/' . $filePath);
                    if (file_exists($fullFilePath)) {
                        unlink($fullFilePath);
                        Log::info('Deleted file', ['path' => $filePath]);
                    }
                }
            }
        }

        $meetingBook->delete();
        return response()->json(['message' => 'Deleted successfully']);
    }

    /**
     * Delete specific documents from a MeetingBook record by MB_Id.
     */
    public function deleteDocuments(Request $request, $id)
    {
        try {
            $meetingBook = MeetingBook::with(['society'])->find($id);
            if (!$meetingBook) {
                return response()->json(['message' => 'Record not found'], 404);
            }

            // Log the incoming request data for debugging
            Log::debug('Delete documents request data:', $request->all());

            // Validate the request
            $validator = Validator::make($request->all(), [
                'indices' => 'required_without:paths|array',
                'indices.*' => 'integer|min:0',
                'paths' => 'required_without:indices|array',
                'paths.*' => 'string|regex:/^meetings\/.+\.(pdf|doc|docx|jpg|jpeg|png)$/i',
            ], [
                'indices.required_without' => 'Either indices or paths must be provided.',
                'paths.required_without' => 'Either indices or paths must be provided.',
                'paths.*.regex' => 'Each path must be a valid file path starting with meetings/ and ending with .pdf, .doc, .docx, .jpg, .jpeg, or .png.'
            ]);

            if ($validator->fails()) {
                Log::error('Validation failed:', $validator->errors()->toArray());
                return response()->json(['errors' => $validator->errors()], 422);
            }

            // Get current file paths
            $filePaths = $meetingBook->Meeting_Doc ? json_decode($meetingBook->Meeting_Doc, true) : [];
            if (empty($filePaths)) {
                return response()->json(['message' => 'No documents to delete'], 400);
            }

            // Determine files to delete
            $filesToDelete = [];
            $newFilePaths = $filePaths;

            if ($request->has('indices')) {
                $indices = array_unique($request->input('indices'));
                foreach ($indices as $index) {
                    if (isset($filePaths[$index])) {
                        $filesToDelete[] = $filePaths[$index];
                        unset($newFilePaths[$index]);
                    } else {
                        Log::warning("Invalid index provided for deletion: {$index}");
                    }
                }
            } elseif ($request->has('paths')) {
                $paths = array_unique($request->input('paths'));
                foreach ($paths as $path) {
                    if (in_array($path, $filePaths)) {
                        $filesToDelete[] = $path;
                        $newFilePaths = array_diff($newFilePaths, [$path]);
                    } else {
                        Log::warning("Invalid path provided for deletion: {$path}");
                    }
                }
            }

            // Delete files from storage
            $basePath = public_path('storage');
            foreach ($filesToDelete as $filePath) {
                $fullPath = $basePath . '/' . $filePath;
                if (file_exists($fullPath)) {
                    unlink($fullPath);
                    Log::info('Deleted document', ['path' => $filePath]);
                }
            }

            // Update the record with remaining files
            $data = [
                'Meeting_Doc' => !empty($newFilePaths) ? json_encode(array_values($newFilePaths)) : null,
            ];
            $meetingBook->update($data);

            // Prepare response with full URLs and formatted dates
            $responseData = $meetingBook->toArray();
            $responseData['STDate'] = $meetingBook->STDate ? Carbon::parse($meetingBook->STDate)->format('d/m/Y H:i:s') : null;
            $responseData['StTime'] = $meetingBook->StTime ? Carbon::parse($meetingBook->StTime)->format('d/m/Y H:i:s') : null;
            $responseData['EdTime'] = $meetingBook->EdTime ? Carbon::parse($meetingBook->EdTime)->format('d/m/Y H:i:s') : null;
            $responseData['Meeting_Doc'] = $meetingBook->Meeting_Doc ? array_map(function ($path) {
                return url('storage/' . $path);
            }, json_decode($meetingBook->Meeting_Doc, true)) : null;
            $responseData['message'] = 'Documents deleted successfully';

            Log::info('MeetingBook documents deleted:', $responseData);

            return response()->json($responseData, 200);
        } catch (\Exception $e) {
            Log::error('Delete documents error:', ['message' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
            return response()->json(['error' => 'Internal Server Error', 'message' => $e->getMessage()], 500);
        }
    }

    /**
     * Get file extension from MIME type.
     */
}
