<?php

namespace App\Services;

use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Http\UploadedFile;

class RecordFileService
{
    /**
     * Get client name from session, fallback to 'default'
     */
    private function getClientName()
    {
        $clientName = session('clientName', 'default');

        $clientName = Str::slug($clientName, '_');

        Log::info("Using client name for folders: {$clientName}");
        return $clientName;
    }

    /**
     * Create record folders with client structure
     */
    public function createRecordFolders($recordId, $type)
    {
        $clientName = $this->getClientName();
        $type = strtolower($type);

        Log::info("Preparing S3 structure for client: {$clientName}, record {$recordId}, type: {$type}");
        $folderPath = "{$clientName}/records/{$type}/{$recordId}/attachments";
        Log::info("S3 folder structure: {$folderPath}");

        return true;
    }

    /**
     * Store file temporarily with client structure
     */
    public function storeTemporarily($uploadedFile)
    {
        try {
            $clientName = $this->getClientName();
            $extension = $uploadedFile->getClientOriginalExtension();
            $fileName = time() . '_' . Str::random(10) . '.' . $extension;
            $tempPath = "{$clientName}/temp/uploads/{$fileName}";

            Log::info("=== STORING FILE TEMPORARILY ===");
            Log::info("Client: {$clientName}");
            Log::info("Original filename: " . $uploadedFile->getClientOriginalName());
            Log::info("File size: " . $uploadedFile->getSize() . " bytes");
            Log::info("Temp path: {$tempPath}");

            try {
                $storedPath = Storage::disk('s3')->putFileAs("{$clientName}/temp/uploads", $uploadedFile, $fileName);
                Log::info("Method 1 success - putFileAs returned: {$storedPath}");

                if (Storage::disk('s3')->exists($tempPath)) {
                    $storedSize = Storage::disk('s3')->size($tempPath);
                    Log::info("File verification successful - size: {$storedSize} bytes");

                    if ($storedSize === $uploadedFile->getSize()) {
                        Log::info("File sizes match perfectly");
                        return $tempPath;
                    } else {
                        Log::warning("⚠ File size mismatch - Original: {$uploadedFile->getSize()}, Stored: {$storedSize}");
                        return $tempPath;
                    }
                } else {
                    throw new \Exception("File not found after putFileAs");
                }
            } catch (\Exception $e) {
                Log::warning("Method 1 failed: " . $e->getMessage());
            }

            try {
                Log::info("Trying Method 2: put with file contents");
                $fileContent = file_get_contents($uploadedFile->getRealPath());

                if (!$fileContent) {
                    throw new \Exception("Could not read file contents");
                }

                $stored = Storage::disk('s3')->put($tempPath, $fileContent);

                if ($stored && Storage::disk('s3')->exists($tempPath)) {
                    Log::info("Method 2 success - put with contents");
                    return $tempPath;
                } else {
                    throw new \Exception("Put method failed");
                }
            } catch (\Exception $e) {
                Log::warning("Method 2 failed: " . $e->getMessage());
            }

            throw new \Exception("All temp storage methods failed");

        } catch (\Exception $e) {
            Log::error("Error storing file temporarily: " . $e->getMessage());
            Log::error("Stack trace: " . $e->getTraceAsString());
            throw $e;
        }
    }

    /**
     * Upload attachment directly to final S3 location with client structure
     */
    public function uploadAttachment($file, $recordId, $type)
    {
        try {
            $clientName = $this->getClientName();
            $type = strtolower($type);
            $extension = $file->getClientOriginalExtension();
            $fileName = time() . '_' . Str::random(10) . '.' . $extension;
            $finalPath = "{$clientName}/records/{$type}/{$recordId}/attachments/{$fileName}";

            Log::info("Uploading attachment to S3:");
            Log::info("- Client: {$clientName}");
            Log::info("- Record ID: {$recordId}");
            Log::info("- Type: {$type}");
            Log::info("- File path: {$finalPath}");
            Log::info("- File size: " . $file->getSize() . " bytes");

            $storedPath = Storage::disk('s3')->putFileAs(
                "{$clientName}/records/{$type}/{$recordId}/attachments",
                $file,
                $fileName
            );

            Log::info("File uploaded successfully to S3: {$storedPath}");

            if (Storage::disk('s3')->exists($finalPath)) {
                Log::info("S3 upload verified successfully");
                return $finalPath;
            } else {
                throw new \Exception("File verification failed - not found on S3");
            }

        } catch (\Exception $e) {
            Log::error("Error uploading attachment to S3: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Upload XML receipt for import functionality with client structure
     */
    public function uploadXmlReceipt($file, $recordId, $type)
    {
        try {
            $clientName = $this->getClientName();
            $type = strtolower($type);
            $extension = $file->getClientOriginalExtension() ?: 'xml';
            $fileName = 'receipt_' . time() . '_' . Str::random(8) . '.' . $extension;
            $finalPath = "{$clientName}/records/{$type}/{$recordId}/attachments/{$fileName}";

            Log::info("Uploading XML receipt to S3:");
            Log::info("- Client: {$clientName}");
            Log::info("- Path: {$finalPath}");

            $storedPath = Storage::disk('s3')->putFileAs(
                "{$clientName}/records/{$type}/{$recordId}/attachments",
                $file,
                $fileName
            );

            Log::info("XML receipt uploaded to S3: {$storedPath}");
            return $finalPath;

        } catch (\Exception $e) {
            Log::error("Error uploading XML receipt to S3: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Get S3 attachment URL
     */
    public function getAttachmentUrl($filePath)
    {
        try {
            if (!$filePath) {
                return null;
            }

            Log::info("Getting S3 attachment URL for: {$filePath}");

            if (!Storage::disk('s3')->exists($filePath)) {
                Log::warning("S3 attachment file not found: {$filePath}");

                $directory = dirname($filePath);
                try {
                    $files = Storage::disk('s3')->files($directory);
                    Log::info("Files in S3 directory {$directory}: " . json_encode($files));
                } catch (\Exception $e) {
                    Log::warning("Could not list S3 directory {$directory}: " . $e->getMessage());
                }

                return null;
            }

            $url = Storage::disk('s3')->temporaryUrl($filePath, now()->addHours(1));
            Log::info("Generated S3 temporary URL for: {$filePath}");
            return $url;

        } catch (\Exception $e) {
            Log::error("Error getting S3 attachment URL for {$filePath}: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Delete attachment from S3
     */
    public function deleteAttachment($filePath)
    {
        try {
            if (!$filePath) {
                return false;
            }

            Log::info("Deleting S3 attachment: {$filePath}");

            if (Storage::disk('s3')->exists($filePath)) {
                $deleted = Storage::disk('s3')->delete($filePath);
                if ($deleted) {
                    Log::info("S3 attachment deleted successfully: {$filePath}");
                    return true;
                } else {
                    Log::error("Failed to delete S3 attachment: {$filePath}");
                    return false;
                }
            } else {
                Log::warning("S3 attachment not found for deletion: {$filePath}");
                return false;
            }
        } catch (\Exception $e) {
            Log::error("Error deleting S3 attachment: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Debug S3 configuration and connectivity
     */
    public function debugFileSystem()
    {
        $clientName = $this->getClientName();

        Log::info("=== S3 DEBUG ===");
        Log::info("Client Name: {$clientName}");
        Log::info("S3 Configuration:");
        Log::info("- Bucket: " . config('filesystems.disks.s3.bucket'));
        Log::info("- Region: " . config('filesystems.disks.s3.region'));
        Log::info("- URL: " . config('filesystems.disks.s3.url'));
        Log::info("- Key: " . (config('filesystems.disks.s3.key') ? 'Set' : 'Not set'));
        Log::info("- Secret: " . (config('filesystems.disks.s3.secret') ? 'Set' : 'Not set'));

        try {
            $testFile = "{$clientName}/test_connection_" . time() . '.txt';
            $testContent = 'S3 connection test: ' . now();

            Log::info("Testing S3 connection with client structure...");
            Storage::disk('s3')->put($testFile, $testContent);

            if (Storage::disk('s3')->exists($testFile)) {
                Log::info("S3 connection test: SUCCESS");
                Storage::disk('s3')->delete($testFile);
            } else {
                Log::error("S3 connection test: FAILED - file not found after upload");
            }
        } catch (\Exception $e) {
            Log::error("S3 connection test: FAILED - " . $e->getMessage());
        }

        Log::info("=== END S3 DEBUG ===");
    }

    /**
     * Clean up old temp files from S3 for specific client or all clients
     */
    public function cleanupTempFiles($olderThanHours = 24, $specificClient = null)
    {
        try {
            $clientName = $specificClient ?: $this->getClientName();
            $tempPath = $specificClient ? "{$specificClient}/temp/uploads" : "{$clientName}/temp/uploads";

            $tempFiles = Storage::disk('s3')->files($tempPath);
            $cutoffTime = now()->subHours($olderThanHours);
            $deletedCount = 0;

            Log::info("Cleaning up S3 temp files for client '{$clientName}' older than {$olderThanHours} hours");

            foreach ($tempFiles as $file) {
                $fileTime = Storage::disk('s3')->lastModified($file);
                if ($fileTime < $cutoffTime->timestamp) {
                    if (Storage::disk('s3')->delete($file)) {
                        $deletedCount++;
                        Log::info("Cleaned up old S3 temp file: {$file}");
                    }
                }
            }

            Log::info("S3 cleanup completed for client '{$clientName}'. Deleted {$deletedCount} temp files.");

        } catch (\Exception $e) {
            Log::error("Error cleaning up S3 temp files: " . $e->getMessage());
        }
    }

    /**
     * Clean up temp files for all clients
     */
    public function cleanupAllClientTempFiles($olderThanHours = 24)
    {
        try {
            $allDirectories = Storage::disk('s3')->directories('');
            $deletedCount = 0;

            Log::info("Cleaning up temp files for all clients older than {$olderThanHours} hours");

            foreach ($allDirectories as $clientDir) {
                $tempPath = "{$clientDir}/temp/uploads";

                if (Storage::disk('s3')->exists($tempPath)) {
                    $tempFiles = Storage::disk('s3')->files($tempPath);
                    $cutoffTime = now()->subHours($olderThanHours);

                    foreach ($tempFiles as $file) {
                        $fileTime = Storage::disk('s3')->lastModified($file);
                        if ($fileTime < $cutoffTime->timestamp) {
                            if (Storage::disk('s3')->delete($file)) {
                                $deletedCount++;
                                Log::info("Cleaned up old S3 temp file: {$file}");
                            }
                        }
                    }
                }
            }

            Log::info("S3 cleanup completed for all clients. Deleted {$deletedCount} temp files.");

        } catch (\Exception $e) {
            Log::error("Error cleaning up all client temp files: " . $e->getMessage());
        }
    }

    /**
     * Check if a file exists on S3
     */
    public function fileExists($filePath)
    {
        try {
            return Storage::disk('s3')->exists($filePath);
        } catch (\Exception $e) {
            Log::error("Error checking if S3 file exists: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Get file size from S3
     */
    public function getFileSize($filePath)
    {
        try {
            if (Storage::disk('s3')->exists($filePath)) {
                return Storage::disk('s3')->size($filePath);
            }
            return 0;
        } catch (\Exception $e) {
            Log::error("Error getting S3 file size: " . $e->getMessage());
            return 0;
        }
    }

    /**
     * Get file last modified time from S3
     */
    public function getFileLastModified($filePath)
    {
        try {
            if (Storage::disk('s3')->exists($filePath)) {
                return Storage::disk('s3')->lastModified($filePath);
            }
            return null;
        } catch (\Exception $e) {
            Log::error("Error getting S3 file last modified: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Get all files for a specific client and type
     */
    public function getClientFiles($type = null, $clientName = null)
    {
        try {
            $clientName = $clientName ?: $this->getClientName();
            $type = $type ? strtolower($type) : '*';

            $basePath = $type === '*' ? "{$clientName}/records" : "{$clientName}/records/{$type}";

            $files = Storage::disk('s3')->allFiles($basePath);
            Log::info("Found " . count($files) . " files for client '{$clientName}' and type '{$type}'");

            return $files;
        } catch (\Exception $e) {
            Log::error("Error getting client files: " . $e->getMessage());
            return [];
        }
    }
}
