package com.storycove.controller;

import com.storycove.service.AsyncBackupService;
import com.storycove.service.DatabaseManagementService;
import com.storycove.service.LibraryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/database")
public class DatabaseController {

    @Autowired
    private DatabaseManagementService databaseManagementService;

    @Autowired
    private AsyncBackupService asyncBackupService;

    @Autowired
    private LibraryService libraryService;

    @PostMapping("/backup")
    public ResponseEntity<Resource> backupDatabase() {
        try {
            Resource backup = databaseManagementService.createBackup();
            
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
            String filename = "storycove_backup_" + timestamp + ".sql";
            
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(backup);
        } catch (Exception e) {
            throw new RuntimeException("Failed to create database backup: " + e.getMessage(), e);
        }
    }

    @PostMapping("/restore")
    public ResponseEntity<Map<String, Object>> restoreDatabase(@RequestParam("file") MultipartFile file) {
        try {
            if (file.isEmpty()) {
                return ResponseEntity.badRequest()
                        .body(Map.of("success", false, "message", "No file uploaded"));
            }

            if (!file.getOriginalFilename().endsWith(".sql")) {
                return ResponseEntity.badRequest()
                        .body(Map.of("success", false, "message", "Invalid file type. Please upload a .sql file"));
            }

            databaseManagementService.restoreFromBackup(file.getInputStream());
            
            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Database restored successfully from " + file.getOriginalFilename()
            ));
        } catch (IOException e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to read backup file: " + e.getMessage()));
        } catch (Exception e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to restore database: " + e.getMessage()));
        }
    }

    @PostMapping("/clear")
    public ResponseEntity<Map<String, Object>> clearDatabase() {
        try {
            int deletedRecords = databaseManagementService.clearAllData();
            
            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Database cleared successfully",
                    "deletedRecords", deletedRecords
            ));
        } catch (Exception e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to clear database: " + e.getMessage()));
        }
    }

    @PostMapping("/backup-complete")
    public ResponseEntity<Map<String, Object>> backupCompleteAsync() {
        try {
            String libraryId = libraryService.getCurrentLibraryId();
            if (libraryId == null) {
                return ResponseEntity.badRequest()
                        .body(Map.of("success", false, "message", "No library selected"));
            }

            // Start backup job asynchronously
            com.storycove.entity.BackupJob job = asyncBackupService.startBackupJob(
                    libraryId,
                    com.storycove.entity.BackupJob.BackupType.COMPLETE
            );

            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Backup started",
                    "jobId", job.getId().toString(),
                    "status", job.getStatus().toString()
            ));
        } catch (Exception e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to start backup: " + e.getMessage()));
        }
    }

    @GetMapping("/backup-status/{jobId}")
    public ResponseEntity<Map<String, Object>> getBackupStatus(@PathVariable String jobId) {
        try {
            java.util.UUID uuid = java.util.UUID.fromString(jobId);
            java.util.Optional<com.storycove.entity.BackupJob> jobOpt = asyncBackupService.getJobStatus(uuid);

            if (jobOpt.isEmpty()) {
                return ResponseEntity.notFound().build();
            }

            com.storycove.entity.BackupJob job = jobOpt.get();

            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "jobId", job.getId().toString(),
                    "status", job.getStatus().toString(),
                    "progress", job.getProgressPercent(),
                    "fileSizeBytes", job.getFileSizeBytes() != null ? job.getFileSizeBytes() : 0,
                    "createdAt", job.getCreatedAt().toString(),
                    "completedAt", job.getCompletedAt() != null ? job.getCompletedAt().toString() : "",
                    "errorMessage", job.getErrorMessage() != null ? job.getErrorMessage() : ""
            ));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest()
                    .body(Map.of("success", false, "message", "Invalid job ID"));
        }
    }

    @GetMapping("/backup-download/{jobId}")
    public ResponseEntity<Resource> downloadBackup(@PathVariable String jobId) {
        try {
            java.util.UUID uuid = java.util.UUID.fromString(jobId);
            Resource backup = asyncBackupService.getBackupFile(uuid);

            java.util.Optional<com.storycove.entity.BackupJob> jobOpt = asyncBackupService.getJobStatus(uuid);
            if (jobOpt.isEmpty()) {
                return ResponseEntity.notFound().build();
            }

            com.storycove.entity.BackupJob job = jobOpt.get();
            String timestamp = job.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
            String extension = job.getType() == com.storycove.entity.BackupJob.BackupType.COMPLETE ? "zip" : "sql";
            String filename = "storycove_backup_" + timestamp + "." + extension;

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
                    .header(HttpHeaders.CONTENT_TYPE,
                            job.getType() == com.storycove.entity.BackupJob.BackupType.COMPLETE
                                    ? "application/zip"
                                    : "application/sql")
                    .body(backup);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        } catch (Exception e) {
            throw new RuntimeException("Failed to download backup: " + e.getMessage(), e);
        }
    }

    @GetMapping("/backup-list")
    public ResponseEntity<Map<String, Object>> listBackups() {
        try {
            String libraryId = libraryService.getCurrentLibraryId();
            if (libraryId == null) {
                return ResponseEntity.badRequest()
                        .body(Map.of("success", false, "message", "No library selected"));
            }

            List<com.storycove.entity.BackupJob> jobs = asyncBackupService.listBackupJobs(libraryId);

            List<Map<String, Object>> jobsList = jobs.stream()
                    .map(job -> {
                        Map<String, Object> jobMap = new java.util.HashMap<>();
                        jobMap.put("jobId", job.getId().toString());
                        jobMap.put("type", job.getType().toString());
                        jobMap.put("status", job.getStatus().toString());
                        jobMap.put("progress", job.getProgressPercent());
                        jobMap.put("fileSizeBytes", job.getFileSizeBytes() != null ? job.getFileSizeBytes() : 0L);
                        jobMap.put("createdAt", job.getCreatedAt().toString());
                        jobMap.put("completedAt", job.getCompletedAt() != null ? job.getCompletedAt().toString() : "");
                        return jobMap;
                    })
                    .collect(java.util.stream.Collectors.toList());

            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "backups", jobsList
            ));
        } catch (Exception e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to list backups: " + e.getMessage()));
        }
    }

    @DeleteMapping("/backup/{jobId}")
    public ResponseEntity<Map<String, Object>> deleteBackup(@PathVariable String jobId) {
        try {
            java.util.UUID uuid = java.util.UUID.fromString(jobId);
            asyncBackupService.deleteBackupJob(uuid);

            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Backup deleted successfully"
            ));
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest()
                    .body(Map.of("success", false, "message", "Invalid job ID"));
        } catch (Exception e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to delete backup: " + e.getMessage()));
        }
    }

    @PostMapping("/restore-complete")
    public ResponseEntity<Map<String, Object>> restoreComplete(@RequestParam("file") MultipartFile file) {
        System.err.println("Complete restore endpoint called with file: " + (file != null ? file.getOriginalFilename() : "null"));
        try {
            if (file.isEmpty()) {
                System.err.println("File is empty - returning bad request");
                return ResponseEntity.badRequest()
                        .body(Map.of("success", false, "message", "No file uploaded"));
            }

            if (!file.getOriginalFilename().endsWith(".zip")) {
                System.err.println("Invalid file type: " + file.getOriginalFilename());
                return ResponseEntity.badRequest()
                        .body(Map.of("success", false, "message", "Invalid file type. Please upload a .zip file"));
            }

            System.err.println("File validation passed, calling restore service...");
            databaseManagementService.restoreFromCompleteBackup(file.getInputStream());
            System.err.println("Restore service completed successfully");
            
            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Complete backup restored successfully from " + file.getOriginalFilename()
            ));
        } catch (IOException e) {
            System.err.println("IOException during restore: " + e.getMessage());
            e.printStackTrace();
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to read backup file: " + e.getMessage()));
        } catch (Exception e) {
            System.err.println("Exception during restore: " + e.getMessage());
            e.printStackTrace();
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to restore complete backup: " + e.getMessage()));
        }
    }

    @PostMapping("/clear-complete")
    public ResponseEntity<Map<String, Object>> clearComplete() {
        try {
            int deletedRecords = databaseManagementService.clearAllDataAndFiles();
            
            return ResponseEntity.ok(Map.of(
                    "success", true,
                    "message", "Database and files cleared successfully",
                    "deletedRecords", deletedRecords
            ));
        } catch (Exception e) {
            return ResponseEntity.internalServerError()
                    .body(Map.of("success", false, "message", "Failed to clear database and files: " + e.getMessage()));
        }
    }
}