package at.ac.tuwien.sepm.assignment.groupphase.operation;

import static junit.framework.TestCase.fail;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.DBOperationDAO;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dao.OperationDAO;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Severity;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Operation.Status;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.ConstructionType;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.dto.Vehicle.VehicleType;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.OperationService;
import at.ac.tuwien.sepm.assignment.groupphase.einsatzverwaltung.service.OperationServiceImpl;
import at.ac.tuwien.sepm.assignment.groupphase.exception.InvalidOperationException;
import at.ac.tuwien.sepm.assignment.groupphase.exception.ServiceException;
import at.ac.tuwien.sepm.assignment.groupphase.util.JDBCConnectionManager;
import java.time.Instant;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;

public class OperationServiceComponentTest {

    private final OperationDAO operationDAO = new DBOperationDAO(new JDBCConnectionManager("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"));
    private final OperationService operationService = new OperationServiceImpl(operationDAO);

    @Test
    public void addOperationTest() {
        Vehicle vehicle =
                Vehicle.builder()
                        .status(Vehicle.Status.FREI_FUNK)
                        .constructionType(ConstructionType.HOCHDACH)
                        .name("BKTW_123")
                        .hasNef(true)
                        .type(VehicleType.BKTW)
                        .build();

        Operation operation =
                Operation.builder()
                        .status(Status.ACTIVE)
                        .opCode("ALP-95E7")
                        .created(Instant.now())
                        .destination("Wiedner Hauptstraße 35, Wien")
                        .additionalInfo("HTU Wien")
                        .severity(Severity.B)
                        .vehicles(List.of(vehicle))
                        .build();
        try {
            //TODO: OPERATION DOES NOT WORK
            Assert.assertThat(operationService.add(operation), is(1L));
        } catch (InvalidOperationException | ServiceException e) {
            fail();
        }
    }

    @Test(expected = InvalidOperationException.class)
    public void addFaultyOperationTest() throws InvalidOperationException {
        Vehicle vehicle =
                Vehicle.builder()
                        .status(Vehicle.Status.FREI_FUNK)
                        .constructionType(ConstructionType.HOCHDACH)
                        .name("BKTW_123")
                        .hasNef(true)
                        .type(VehicleType.BKTW)
                        .build();
        Vehicle vehicle1 =
                Vehicle.builder()
                        .status(Vehicle.Status.ABGEMELDET)
                        .constructionType(ConstructionType.HOCHDACH)
                        .name("BKTW_123")
                        .hasNef(true)
                        .type(VehicleType.BKTW)
                        .build();

        Operation operation =
                Operation.builder()
                        .status(Status.ACTIVE)
                        .opCode("ALP-95E7")
                        .created(Instant.now())
                        .destination("Wiedner Hauptstraße 35, Wien")
                        .additionalInfo("HTU Wien")
                        .severity(Severity.B)
                        .vehicles(List.of(vehicle, vehicle1))
                        .build();
        try {
            Assert.assertThat(operationService.add(operation), is(1L));
        } catch (ServiceException e) {
            fail();
        }
    }

    @Test(expected = InvalidOperationException.class)
    public void addFaultyOperation2Test() throws InvalidOperationException {
        Operation operation =
                Operation.builder()
                        .status(Status.ACTIVE)
                        .opCode("ALP-95E7")
                        .created(Instant.now())
                        .destination("Wiedner Hauptstraße 35, Wien")
                        .additionalInfo("HTU Wien")
                        .severity(Severity.B)
                        .vehicles(List.of())
                        .build();
        try {
            Assert.assertThat(operationService.add(operation), is(1L));
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }

    @Test(expected = InvalidOperationException.class)
    public void addFaultyOperation3Test() throws InvalidOperationException {
        Operation operation =
                Operation.builder()
                        .status(Status.ACTIVE)
                        .opCode("ALP-95E7")
                        .created(Instant.now())
                        .destination("")
                        .additionalInfo("HTU Wien")
                        .severity(Severity.B)
                        .vehicles(List.of())
                        .build();
        try {
            Assert.assertThat(operationService.add(operation), is(1L));
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }

    @Test(expected = InvalidOperationException.class)
    public void addFaultyOperation4Test() throws InvalidOperationException {
        Operation operation =
                Operation.builder()
                        .status(Status.ACTIVE)
                        .opCode("")
                        .created(Instant.now())
                        .destination("Römergasse 7, 2500 Baden")
                        .additionalInfo("HTU Wien")
                        .severity(Severity.B)
                        .vehicles(List.of())
                        .build();
        try {
            Assert.assertThat(operationService.add(operation), is(1L));
        } catch (ServiceException e) {
            e.printStackTrace();
        }
    }

}