package be.seeseepuff.allowanceplanner.controller;

import be.seeseepuff.allowanceplanner.dto.*;
import be.seeseepuff.allowanceplanner.service.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*")
public class ApiController {
    private final UserService userService;
    private final AllowanceService allowanceService;
    private final TaskService taskService;
    private final TransferService transferService;
    private final MigrationService migrationService;

    public ApiController(UserService userService,
                         AllowanceService allowanceService,
                         TaskService taskService,
                         TransferService transferService,
                         MigrationService migrationService) {
        this.userService = userService;
        this.allowanceService = allowanceService;
        this.taskService = taskService;
        this.transferService = transferService;
        this.migrationService = migrationService;
    }

    // ---- Users ----

    @GetMapping("/users")
    public List<UserDto> getUsers() {
        return userService.getUsers();
    }

    @GetMapping("/user/{userId}")
    public ResponseEntity<?> getUser(@PathVariable String userId) {
        int id;
        try {
            id = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        Optional<UserWithAllowanceDto> user = userService.getUser(id);
        if (user.isEmpty()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }
        return ResponseEntity.ok(user.get());
    }

    // ---- History ----

    @PostMapping("/user/{userId}/history")
    public ResponseEntity<?> postHistory(@PathVariable String userId, @RequestBody PostHistoryRequest request) {
        int id;
        try {
            id = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        if (request.description() == null || request.description().isEmpty()) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Description cannot be empty"));
        }

        if (!userService.userExists(id)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        allowanceService.addHistory(id, request);
        return ResponseEntity.ok(new MessageResponse("History updated successfully"));
    }

    @GetMapping("/user/{userId}/history")
    public ResponseEntity<?> getHistory(@PathVariable String userId) {
        int id;
        try {
            id = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        List<HistoryDto> history = allowanceService.getHistory(id);
        return ResponseEntity.ok(history);
    }

    // ---- Allowances ----

    @GetMapping("/user/{userId}/allowance")
    public ResponseEntity<?> getUserAllowance(@PathVariable String userId) {
        int id;
        try {
            id = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        if (!userService.userExists(id)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        return ResponseEntity.ok(allowanceService.getUserAllowances(id));
    }

    @PostMapping("/user/{userId}/allowance")
    public ResponseEntity<?> createUserAllowance(@PathVariable String userId,
                                                 @RequestBody CreateAllowanceRequest request) {
        int id;
        try {
            id = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        if (request.name() == null || request.name().isEmpty()) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Allowance name cannot be empty"));
        }

        if (!userService.userExists(id)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        int allowanceId = allowanceService.createAllowance(id, request);
        return ResponseEntity.status(HttpStatus.CREATED).body(new IdResponse(allowanceId));
    }

    @PutMapping("/user/{userId}/allowance")
    public ResponseEntity<?> bulkPutUserAllowance(@PathVariable String userId,
                                                  @RequestBody List<BulkUpdateAllowanceRequest> requests) {
        int id;
        try {
            id = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        if (!userService.userExists(id)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        allowanceService.bulkUpdateAllowance(id, requests);
        return ResponseEntity.ok(new MessageResponse("Allowance updated successfully"));
    }

    @GetMapping("/user/{userId}/allowance/{allowanceId}")
    public ResponseEntity<?> getUserAllowanceById(@PathVariable String userId, @PathVariable String allowanceId) {
        int uid;
        try {
            uid = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        int aid;
        try {
            aid = Integer.parseInt(allowanceId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid allowance ID"));
        }

        if (!userService.userExists(uid)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        Optional<AllowanceDto> allowance = allowanceService.getUserAllowanceById(uid, aid);
        if (allowance.isEmpty()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Allowance not found"));
        }
        return ResponseEntity.ok(allowance.get());
    }

    @DeleteMapping("/user/{userId}/allowance/{allowanceId}")
    public ResponseEntity<?> deleteUserAllowance(@PathVariable String userId, @PathVariable String allowanceId) {
        int uid;
        try {
            uid = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        int aid;
        try {
            aid = Integer.parseInt(allowanceId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid allowance ID"));
        }

        if (aid == 0) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Allowance id zero cannot be deleted"));
        }

        if (!userService.userExists(uid)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        boolean deleted = allowanceService.deleteAllowance(uid, aid);
        if (!deleted) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("History not found"));
        }
        return ResponseEntity.ok(new MessageResponse("History deleted successfully"));
    }

    @PutMapping("/user/{userId}/allowance/{allowanceId}")
    public ResponseEntity<?> putUserAllowance(@PathVariable String userId, @PathVariable String allowanceId,
                                              @RequestBody UpdateAllowanceRequest request) {
        int uid;
        try {
            uid = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        int aid;
        try {
            aid = Integer.parseInt(allowanceId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid allowance ID"));
        }

        if (!userService.userExists(uid)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        boolean updated = allowanceService.updateAllowance(uid, aid, request);
        if (!updated) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Allowance not found"));
        }
        return ResponseEntity.ok(new MessageResponse("Allowance updated successfully"));
    }

    @PostMapping("/user/{userId}/allowance/{allowanceId}/complete")
    public ResponseEntity<?> completeAllowance(@PathVariable String userId, @PathVariable String allowanceId) {
        int uid;
        try {
            uid = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        int aid;
        try {
            aid = Integer.parseInt(allowanceId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid allowance ID"));
        }

        if (!userService.userExists(uid)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        boolean completed = allowanceService.completeAllowance(uid, aid);
        if (!completed) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Allowance not found"));
        }
        return ResponseEntity.ok(new MessageResponse("Allowance completed successfully"));
    }

    @PostMapping("/user/{userId}/allowance/{allowanceId}/add")
    public ResponseEntity<?> addToAllowance(@PathVariable String userId, @PathVariable String allowanceId,
                                            @RequestBody AddAllowanceAmountRequest request) {
        int uid;
        try {
            uid = Integer.parseInt(userId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid user ID"));
        }

        int aid;
        try {
            aid = Integer.parseInt(allowanceId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid allowance ID"));
        }

        if (!userService.userExists(uid)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
        }

        boolean result = allowanceService.addAllowanceAmount(uid, aid, request);
        if (!result) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Allowance not found"));
        }
        return ResponseEntity.ok(new MessageResponse("Allowance completed successfully"));
    }

    // ---- Tasks ----

    @PostMapping("/tasks")
    public ResponseEntity<?> createTask(@RequestBody CreateTaskRequest request) {
        if (request.name() == null || request.name().isEmpty()) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Task name cannot be empty"));
        }

        if (request.schedule() != null) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Schedules are not yet supported"));
        }

        if (request.assigned() != null) {
            if (!userService.userExists(request.assigned())) {
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("User not found"));
            }
        }

        int taskId = taskService.createTask(request);
        return ResponseEntity.status(HttpStatus.CREATED).body(new IdResponse(taskId));
    }

    @GetMapping("/tasks")
    public List<TaskDto> getTasks() {
        return taskService.getTasks();
    }

    @GetMapping("/task/{taskId}")
    public ResponseEntity<?> getTask(@PathVariable String taskId) {
        int id;
        try {
            id = Integer.parseInt(taskId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid task ID"));
        }

        Optional<TaskDto> task = taskService.getTask(id);
        if (task.isEmpty()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Task not found"));
        }
        return ResponseEntity.ok(task.get());
    }

    @PutMapping("/task/{taskId}")
    public ResponseEntity<?> putTask(@PathVariable String taskId, @RequestBody CreateTaskRequest request) {
        int id;
        try {
            id = Integer.parseInt(taskId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid task ID"));
        }

        Optional<TaskDto> existing = taskService.getTask(id);
        if (existing.isEmpty()) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Task not found"));
        }

        taskService.updateTask(id, request);
        return ResponseEntity.ok(new MessageResponse("Task updated successfully"));
    }

    @DeleteMapping("/task/{taskId}")
    public ResponseEntity<?> deleteTask(@PathVariable String taskId) {
        int id;
        try {
            id = Integer.parseInt(taskId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid task ID"));
        }

        if (!taskService.hasTask(id)) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Task not found"));
        }

        taskService.deleteTask(id);
        return ResponseEntity.ok(new MessageResponse("Task deleted successfully"));
    }

    @PostMapping("/task/{taskId}/complete")
    public ResponseEntity<?> completeTask(@PathVariable String taskId) {
        int id;
        try {
            id = Integer.parseInt(taskId);
        } catch (NumberFormatException e) {
            return ResponseEntity.badRequest().body(new ErrorResponse("Invalid task ID"));
        }

        boolean completed = taskService.completeTask(id);
        if (!completed) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("Task not found"));
        }
        return ResponseEntity.ok(new MessageResponse("Task completed successfully"));
    }

    // ---- Transfer ----

    @PostMapping("/transfer")
    public ResponseEntity<?> transfer(@RequestBody TransferRequest request) {
        TransferService.TransferResult result = transferService.transfer(request);
        return switch (result.status()) {
            case SUCCESS -> ResponseEntity.ok(new MessageResponse(result.message()));
            case BAD_REQUEST -> ResponseEntity.badRequest().body(new ErrorResponse(result.message()));
            case NOT_FOUND -> ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse(result.message()));
        };
    }

    // ---- Migration ----

    @PostMapping("/import")
    public ResponseEntity<?> importData(@RequestBody MigrationDto data) {
        migrationService.importData(data);
        return ResponseEntity.ok(new MessageResponse("Import successful"));
    }
}
