package com.spring.data.jpa.datajpa.controller;

import com.spring.data.jpa.datajpa.entity.Customer;
import com.spring.data.jpa.datajpa.exception.BusinessException;
import com.spring.data.jpa.datajpa.implementation.CutomCustomerRepoImlp;
import com.spring.data.jpa.datajpa.repository.CustomCustomerRepository;
import com.spring.data.jpa.datajpa.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.UnexpectedRollbackException;
import org.springframework.web.bind.annotation.*;

import javax.websocket.server.PathParam;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired
    private CustomerRepository customerRepository;

    @GetMapping(value = "/getAllCustomers")
    public ResponseEntity<List<Customer>> getAllCustomers() {
        Iterable<Customer> customerList = customerRepository.findAll();
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/getCustomerById/{id}")
    public ResponseEntity<Customer> getCustomerById(@PathVariable Long id) {
        Optional<Customer> customer = customerRepository.findById(id);
        return new ResponseEntity(customer, HttpStatus.OK);
    }

    @GetMapping(value = "/findByIdAsyncTest/{id}")
    public ResponseEntity<Customer> findByIdAsyncTest(@PathVariable Long id) throws ExecutionException, InterruptedException {
        Future<Customer> customer = customerRepository.findByIdAsyncTest(id);
        return new ResponseEntity(customer.get(), HttpStatus.OK);
    }

    @PostMapping(value = "/addCustomers", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> addCustomers(@RequestBody List<Customer> customer) throws BusinessException {
        try {
            customerRepository.saveAll(customer);
        } catch (UnexpectedRollbackException ex) {
            if (ex.getMostSpecificCause() instanceof SQLIntegrityConstraintViolationException) {
                throw new BusinessException("constraint violation", ex);
            }
        }
        return new ResponseEntity("Customers Added Successfully", HttpStatus.CREATED);
    }

    @GetMapping(value = "/getByLastName")
    public ResponseEntity<List<Customer>> getByLastName(@PathParam("lastName") String lastName) {
        List<Customer> customerList = customerRepository.findByLastName(lastName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/findByGreaterId/{id}")
    public ResponseEntity<List<Customer>> findByGreaterId(@PathVariable Long id) {
        List<Customer> customerList = customerRepository.findByGreaterId(id);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/testOfPositionParams")
    public ResponseEntity<List<Customer>> testOfPositionParams(@PathParam("firstName") String firstName, @PathParam("lastName") String lastName) {
        List<Customer> customerList = customerRepository.testOfPositionParams(firstName, lastName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/tesOfNamedParams")
    public ResponseEntity<List<Customer>> tesOfNamedParams(@PathParam("firstName") String firstName, @PathParam("lastName") String lastName) {
        List<Customer> customerList = customerRepository.tesOfNamedParams(firstName, lastName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/countByLastName")
    public ResponseEntity<Integer> countByLastName(@PathParam("lastName") String lastName) {
        int count = customerRepository.countByLastName(lastName);
        return new ResponseEntity(count, HttpStatus.OK);
    }

    @GetMapping(value = "/findDistinctByFirstName")
    public ResponseEntity<List<Customer>> findDistinctByFirstName(@PathParam("firstName") String firstName) {
        List<Customer> customerList = customerRepository.findDistinctByFirstName(firstName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/findFirst3ByFirstNameOrderByFirstNameAsc")
    public ResponseEntity<List<Customer>> findFirst3ByFirstNameOrderByFirstNameAsc(@PathParam("firstName") String firstName) {
        List<Customer> customerList = customerRepository.findFirst3ByFirstNameOrderByFirstNameAsc(firstName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/findByFirstNameAndLastName")
    public ResponseEntity<List<Customer>> findByFirstNameAndLastName(@PathParam("firstName") String firstName, @PathParam("lastName") String lastName) {
        List<Customer> customerList = customerRepository.findByFirstNameAndLastName(firstName, lastName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping(value = "/findByLastNameOrderByIdAsc")
    public ResponseEntity<List<Customer>> findByLastNameOrderByIdAsc(@PathParam("lastName") String lastName) {
        List<Customer> customerList = customerRepository.findByLastNameOrderByIdAsc(lastName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @PutMapping(value = "/updateLastNameById")
    public ResponseEntity<String> updateLastNameById(@PathParam("lastName") String lastName, @PathParam("id") Long id) {
        int updateCount = customerRepository.updateLastNameById(lastName, id);
        return new ResponseEntity(updateCount + " Customer Updated.", HttpStatus.OK);
    }

    @DeleteMapping(value = "/deleteById/{id}")
    public ResponseEntity<String> deleteById(@PathVariable Long id) throws BusinessException {
        try {
            customerRepository.deleteById(id);
        } catch (UnexpectedRollbackException ex) {
            if (ex.getMostSpecificCause() instanceof SQLException) {
                throw new BusinessException("Update failed due to :: ", ex);
            }
        }
        return new ResponseEntity("Customer Deleted Successfully...", HttpStatus.OK);
    }

    @GetMapping(value = "/findByFirstName")
    public ResponseEntity<List<Customer>> findByFirstName(@PathParam("firstName") String firstName) {
        List<Customer> customerList = customerRepository.findByFirstName(firstName);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping("/findAllByPage")
    public ResponseEntity<List<Customer>> findAllByPage(@PathParam("pageNumber") int pageNumber) {
        Pageable page = PageRequest.of(pageNumber, 5);
        Page<Customer> customerList = customerRepository.findAll(page);
        return new ResponseEntity(customerList.toList(), HttpStatus.OK);
    }

    @GetMapping("/findAllByPageLastName")
    public ResponseEntity<List<Customer>> findAllByPageLastName(@PathParam("lastName") String lastName) {
        Pageable page = PageRequest.of(0, 2);
        List<Customer> customerList = customerRepository.findAllByLastName(lastName, page);
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    //Normal Sorting
    @GetMapping("/normalSorting")
    public ResponseEntity<List<Customer>> normalSorting() {
        List<Customer> customerList = customerRepository.findAll(Sort.by("lastName"));
        return new ResponseEntity(customerList, HttpStatus.OK);
    }

    @GetMapping("/sortWithPagination")
    public ResponseEntity<List<Customer>> sortWithPagination() {
        Pageable sortedByFirstName =
                PageRequest.of(0, 3, Sort.by("firstName"));

        Pageable sortedById =
                PageRequest.of(0, 3, Sort.by("id").descending());

        Pageable sortedByIdDescLastName =
                PageRequest.of(0, 5, Sort.by("id").ascending().and(Sort.by("lastName")));

        Page<Customer> customerList = customerRepository.findAll(sortedById);
        return new ResponseEntity(customerList.toList(), HttpStatus.OK);
    }

    @GetMapping(value = "fetchAllCustomerBySP")
    public ResponseEntity<String> fetchAllCustomerBySP() {
        List<Object[]> objectMap = customerRepository.fetchAllCustomers();
        System.out.println("objectMap :: " +objectMap.size());
        return new ResponseEntity("kjs" ,HttpStatus.OK);
    }

    @GetMapping(value = "getAllCustomersBySP")
    public ResponseEntity<List<Customer>> getAllCustomersBySP() {
        List<Customer> customerList = customerRepository.getAllCustomers();
        return new ResponseEntity(customerList ,HttpStatus.OK);
    }


}