<?php

namespace App\Http\Controllers\api\v1;

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\BaseController;

class FilesControllerREST extends BaseController
{
    /**
     * Store a newly created resource in storage.
     *
     * @return Response
     */
    public function store()
    {
        $uploadedFiles = request()->file('files');
        $relatedId = request()->get('related_id') ?: request()->get('related-id');
        $relatedType = request()->get('related_type') ?: request()->get('related-type', 'task');
        
        if (!$uploadedFiles) {
            return Response::json(['error' => 'No files uploaded'], 400);
        }

        if (!$relatedId) {
            return Response::json(['error' => 'Related ID is required'], 400);
        }

        // Handle single file or multiple files
        if (!is_array($uploadedFiles)) {
            $uploadedFiles = [$uploadedFiles];
        }

        $responses = [];
        $errors = [];

        foreach ($uploadedFiles as $file) {
            try {
                // Check if file is valid and uploaded properly
                if (!$file || !$file->isValid()) {
                    $errors[] = 'Invalid file upload: ' . ($file ? $file->getErrorMessage() : 'No file received');
                    continue;
                }

                // Get file info safely like Laravel5
                $originalName = $file->getClientOriginalName();
                $extension = $file->getClientOriginalExtension();
                
                // Laravel5 compatible filename generation: name.extension.extension
                $filename = $originalName . '.' . $extension;
                
                // Get file size safely
                $fileSize = 0;
                try {
                    $fileSize = $file->getSize();
                } catch (\Exception $e) {
                    // Fallback: try to get size from path
                    if ($file->getPath() && file_exists($file->getPath())) {
                        $fileSize = filesize($file->getPath());
                    }
                }
                
                // Prepare data like Laravel5
                $data = [
                    'name' => $originalName,
                    'size' => $fileSize,
                    'filename' => $filename,
                    'related_id' => $relatedId,
                    'related_type' => $relatedType,
                ];
                
                // Use Laravel5 compatible file storage
                $destinationPath = config('files.path');
                
                // Ensure directory exists
                if (!file_exists($destinationPath)) {
                    mkdir($destinationPath, 0755, true);
                }
                
                // Move file to Laravel5 compatible location
                if ($file->move($destinationPath, $filename)) {
                    // Success - create using Files model like Laravel5
                    $File = \App\Models\Files::create($data);
                    
                    if ($File->id) {
                        // Load creator relationship like Laravel5
                        $File->load('creator');
                        $responses[] = $File;
                    } else {
                        // Delete the file if model creation failed
                        if (file_exists($destinationPath . '/' . $filename)) {
                            unlink($destinationPath . '/' . $filename);
                        }
                        $errors[] = 'Failed to save file record for: ' . $originalName;
                    }
                } else {
                    $errors[] = 'Unable to save file: ' . $originalName;
                }

            } catch (\Exception $e) {
                $errors[] = 'Failed to upload ' . ($file ? $file->getClientOriginalName() : 'unknown file') . ': ' . $e->getMessage();
            }
        }

        // Return like Laravel5 - if single file, return the model directly
        if (count($responses) === 1 && count($errors) === 0) {
            return Response::json($responses[0]);
        }

        // For multiple files or errors, return structured response
        $response = [
            'success' => count($responses) > 0,
            'files' => $responses,
        ];

        if (count($responses) > 0) {
            $response['message'] = count($responses) . ' file(s) uploaded successfully';
        }

        if (count($errors) > 0) {
            $response['errors'] = $errors;
            $response['message'] = isset($response['message']) 
                ? $response['message'] . '. ' . count($errors) . ' file(s) failed.'
                : count($errors) . ' file(s) failed to upload.';
        }

        $statusCode = count($responses) > 0 ? 200 : 400;
        return Response::json($response, $statusCode);
    }

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        $objectType = request()->get('objectType', 'task');
        $objectId = request()->get('objectId');

        if (!$objectId) {
            return Response::json(['error' => 'Object ID is required'], 400);
        }

        // Use Laravel5 compatible get method
        return $this->get($objectType, $objectId);
    }

    /**
     * Display a listing of files with filters.
     *
     * @return Response
     */
    public function getFiles()
    {
        $query = DB::table('files')
            ->select('files.*', 'users.first_name', 'users.last_name')
            ->leftJoin('users', 'users.id', '=', 'files.created_by');

        if (request()->get('all') && request()->get('all') != 'false') {
            // Get all files
        }

        if (request()->get('modifiedSince')) {
            $query->where('files.updated_at', '>=', request()->get('modifiedSince'));
        }

        if (request()->get('assigned_to')) {
            $query->join('tasks', 'tasks.id', '=', 'files.related_id')
                  ->where('files.related_type', '=', request()->get('type', 'task'));
            $query->where('tasks.assigned_to', '=', request()->get('assigned_to'));
        }

        if (request()->get('task_type')) {
            $query->join('tasks', 'tasks.id', '=', 'files.related_id')
                  ->where('files.related_type', '=', request()->get('type', 'task'));
            $query->where('tasks.type', '=', request()->get('task_type'));
        }

        if (request()->get('completed') && request()->get('completed') != 'false') {
            $query->join('tasks', 'tasks.id', '=', 'files.related_id')
                  ->where('files.related_type', '=', request()->get('type', 'task'));
            $query->where('tasks.completed', '=', 1);
        }

        if (request()->get('open') && request()->get('open') != 'false') {
            $query->join('tasks', 'tasks.id', '=', 'files.related_id')
                  ->where('files.related_type', '=', request()->get('type', 'task'));
            $query->where('tasks.completed', '=', 0);
        }

        $query = $query->paginate(request()->get('limit', 20));

        $response = [
            'success'      => true,
            'data'         => $query->getCollection()->toArray(),
            'total'        => $query->total(),
            'current_page' => $query->currentPage(),
            'last_page'    => $query->lastPage(),
        ];

        return Response::json($response);
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        // Use Files model like Laravel5
        $file = \App\Models\Files::findOrFail($id);

        // Load creator relationship like Laravel5
        return Response::json($file->load('creator'));
    }

    /**
     * Download a file.
     *
     * @param  int  $id
     * @return Response
     */
    public function download($id)
    {
        // Use Files model like Laravel5
        $file = \App\Models\Files::findOrFail($id);

        // Try multiple file path locations to support both old and new files
        $filePaths = [
            // Primary: Laravel5 compatible file path
            config('files.path') . '/' . $file->filename,
            
            // Fallback paths for legacy files
            storage_path('app/uploads/' . $file->filename),
            storage_path('files/' . $file->filename),
            base_path('storage/files/' . $file->filename),
        ];

        $actualFilePath = null;
        
        foreach ($filePaths as $path) {
            if (file_exists($path) && is_readable($path)) {
                $actualFilePath = $path;
                break;
            }
        }

        if (!$actualFilePath) {
            return Response::json(['error' => 'File not found in storage'], 404);
        }

        try {
            // Use Laravel5 compatible download method
            $output = response()->download($actualFilePath, $file->name);
            
            // Clear output buffer like Laravel5
            if (ob_get_level()) {
                ob_end_clean();
            }

            return $output;
        } catch (\Exception $e) {
            return Response::json([
                'error' => 'Failed to download file: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return Response
     */
    public function destroy($id)
    {
        // Use Files model like Laravel5
        $file = \App\Models\Files::findOrFail($id);

        // Try multiple file path locations to support both old and new files
        $filePaths = [
            config('files.path') . '/' . $file->filename,
            storage_path('app/uploads/' . $file->filename),
            storage_path('files/' . $file->filename),
            base_path('storage/files/' . $file->filename),
        ];

        $fileDeleted = false;
        foreach ($filePaths as $path) {
            if (file_exists($path)) {
                try {
                    unlink($path);
                    $fileDeleted = true;
                    break;
                } catch (\Exception $e) {
                    // Continue trying other paths
                }
            }
        }

        if ($fileDeleted) {
            // Delete model record like Laravel5
            $result = $file->toArray();
            $file->delete();
            return Response::json($result);
        }

        return Response::json(['error' => 'Failed to delete the file.'], 404);
    }

    /**
     * Upload files - alias for store method.
     *
     * @return Response
     */
    public function upload()
    {
        return $this->store();
    }

    /**
     * Get files for a specific object type and ID (Laravel5 compatible).
     *
     * @param  string  $object
     * @param  int  $id
     * @return Response
     */
    public function get($object, $id)
    {
        // Use Files model with relationships like Laravel5
        $query = \App\Models\Files::where('related_type', $object)
            ->where('related_id', $id)
            ->with('creator')
            ->orderBy('id', 'desc')
            ->paginate(request()->get('limit', 20));

        // Get the collection and ensure creator relationship is properly loaded
        $data = $query->getCollection()->map(function ($file) {
            $fileArray = $file->toArray();
            
            // Ensure creator is properly formatted
            if ($file->creator) {
                $fileArray['creator'] = [
                    'id' => $file->creator->id,
                    'name' => $file->creator->name, // This will use the getNameAttribute method
                    'first_name' => $file->creator->first_name,
                    'last_name' => $file->creator->last_name,
                ];
            }
            
            return $fileArray;
        });

        // Format response like Laravel5
        $response = [
            'success' => true,
            'data' => $data->toArray(),
            'total' => $query->total(),
            'current_page' => $query->currentPage(),
            'last_page' => $query->lastPage(),
            'from' => $query->firstItem(),
            'to' => $query->lastItem(),
        ];

        return Response::json($response);
    }

    /**
     * Get PHP upload configuration limits.
     *
     * @return Response
     */
    public function config()
    {
        // Helper function to convert PHP size strings to bytes
        $convertToBytes = function($value) {
            $value = trim($value);
            $last = strtolower($value[strlen($value)-1]);
            $value = (int) $value;
            
            switch($last) {
                case 'g':
                    $value *= 1024;
                case 'm':
                    $value *= 1024;
                case 'k':
                    $value *= 1024;
            }
            
            return $value;
        };

        // Get PHP upload limits
        $uploadMaxFilesize = ini_get('upload_max_filesize');
        $postMaxSize = ini_get('post_max_size');
        $maxFileUploads = ini_get('max_file_uploads');
        
        // Convert to bytes for calculation
        $uploadMaxBytes = $convertToBytes($uploadMaxFilesize);
        $postMaxBytes = $convertToBytes($postMaxSize);
        
        // The effective limit is the smaller of upload_max_filesize and post_max_size
        $effectiveMaxBytes = min($uploadMaxBytes, $postMaxBytes);
        
        $config = [
            'upload_max_filesize' => $uploadMaxFilesize,
            'upload_max_filesize_bytes' => $uploadMaxBytes,
            'post_max_size' => $postMaxSize,
            'post_max_size_bytes' => $postMaxBytes,
            'max_file_uploads' => (int) $maxFileUploads,
            'effective_max_filesize_bytes' => $effectiveMaxBytes,
            'effective_max_filesize_mb' => round($effectiveMaxBytes / 1024 / 1024, 2),
        ];

        return Response::json([
            'success' => true,
            'data' => $config
        ]);
    }
}
