package de.avatic.lcc.service.bulk;

import de.avatic.lcc.dto.bulk.BulkFileType;
import de.avatic.lcc.dto.bulk.BulkOperationDTO;
import de.avatic.lcc.dto.bulk.BulkOperationState;
import de.avatic.lcc.dto.bulk.BulkProcessingType;
import de.avatic.lcc.model.bulk.BulkOperation;
import de.avatic.lcc.repositories.bulk.BulkOperationRepository;
import de.avatic.lcc.repositories.rates.ValidityPeriodRepository;
import de.avatic.lcc.service.transformer.bulk.BulkOperationTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.badrequest.FileFormatNotSupportedException;
import de.avatic.lcc.util.exception.base.ForbiddenException;
import de.avatic.lcc.util.exception.base.InternalErrorException;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;

@Service
public class BulkOperationService {


    private final BulkOperationRepository bulkOperationRepository;
    private final ValidityPeriodRepository validityPeriodRepository;
    private final BulkOperationTransformer bulkOperationTransformer;
    private final BulkOperationExecutionService bulkOperationExecutionService;
    private final AuthorizationService authorizationService;

    public BulkOperationService(BulkOperationRepository bulkOperationRepository, ValidityPeriodRepository validityPeriodRepository, BulkOperationTransformer bulkOperationTransformer, BulkOperationExecutionService bulkOperationExecutionService, AuthorizationService authorizationService) {
        this.bulkOperationRepository = bulkOperationRepository;
        this.validityPeriodRepository = validityPeriodRepository;
        this.bulkOperationTransformer = bulkOperationTransformer;
        this.bulkOperationExecutionService = bulkOperationExecutionService;
        this.authorizationService = authorizationService;
    }


    public void processFileImport(BulkFileType fileType, MultipartFile file) {

        var userId = authorizationService.getUserId();
        checkAuthorized(fileType);


        String contentType = file.getContentType();
        if (!"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType) &&
                !"application/vnd.ms-excel".equals(contentType)) {
            throw new FileFormatNotSupportedException(contentType);
        }

        try {

            BulkOperation op = new BulkOperation();

            op.setFileType(fileType);
            op.setUserId(userId);
            op.setProcessState(BulkOperationState.SCHEDULED);
            op.setProcessingType(BulkProcessingType.IMPORT);
            op.setFile(file.getInputStream().readAllBytes());
            op.setValidityPeriodId(null);

            var opId = bulkOperationRepository.insert(op);
            bulkOperationExecutionService.launchExecution(opId);


        } catch (IOException e) {
            throw new ExcelValidationError("Unable to read uploaded file.");
        }
    }

    private void checkAuthorized(BulkFileType fileType) {

        var auth = switch (fileType) {
            case CONTAINER_RATE, COUNTRY_MATRIX -> authorizationService.hasAnyRole("SUPER", "FREIGHT");
            case MATERIAL -> authorizationService.hasAnyRole("SUPER", "MATERIAL");
            case PACKAGING -> authorizationService.hasAnyRole("SUPER", "PACKAGING");
            case NODE -> authorizationService.hasAnyRole("SUPER");
        };

        if(!auth) {
            throw new ForbiddenException("You are not authorized to perform this operation");
        }

    }

    public void processFileExport(BulkFileType type, Integer validityPeriodId) {
        var userId = authorizationService.getUserId();

        BulkOperation op = new BulkOperation();
        op.setUserId(userId);
        op.setFileType(type);
        op.setProcessingType(BulkProcessingType.EXPORT);
        op.setProcessState(BulkOperationState.SCHEDULED);
        op.setValidityPeriodId(validityPeriodId);

        var opId = bulkOperationRepository.insert(op);
        bulkOperationExecutionService.launchExecution(opId);
    }

    public void processFileExport(BulkFileType type) {
        processFileExport(type, validityPeriodRepository.getValidPeriodId().orElseThrow(() -> new InternalErrorException("No valid period found that is VALID")));
    }

    public List<BulkOperationDTO> getStatus() {
        var userId = authorizationService.getUserId();
        return bulkOperationRepository.listByUserId(userId).stream().map(bulkOperationTransformer::toBulkOperationDTO).toList();
    }

    public BulkOperation getBulkOperation(Integer id) {
        return bulkOperationRepository.getOperationById(id).orElseThrow();
    }

}
