package pedidos.pedidos.core.pedidos;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import pedidos.pedidos.core.cliente.ClienteService;

@RestController
@RequestMapping("/api/pedido")
@CrossOrigin({"*"})
public class PedidoController {
    
    @Autowired
    PedidoService service;
    @Autowired ClienteService clienteService;

    @GetMapping("/{id}/")
    public Pedido findById(@PathVariable Integer id){
        return service.findById(id);
    }

    @GetMapping("/")
    public List<Pedido> findAll(){
        return service.findAll();
    }

    //Create
    //Delimitador de acceso (public, private), tipo de dato de retorno, nombre del método, parametros de entrada { Sentencias }
    @PostMapping("/")
    public Pedido save (@RequestBody Pedido entity ){
        return service.save(entity);
    }

    @PutMapping("/")
    public Pedido update (@RequestBody Pedido entity){
        return service.save(entity);
    }

    @DeleteMapping("/{id}/")
    public void deleteById(@PathVariable Integer id){
        service.deleteById(id);
    }

    @PatchMapping("/{id}/")
    public Pedido partialUpdate(@PathVariable long id, @RequestBody Map<String, Object> fields){

        Pedido entity = service.findById(id);

        // itera sobre los campos que se desean actualizar
        for (Map.Entry<String, Object> field : fields.entrySet()) {
            String fieldName = field.getKey();
            Object fieldValue = null;
            ObjectMapper mapper = new ObjectMapper();
            mapper.registerModule(new JavaTimeModule());
            java.lang.reflect.Field campoEntidad = org.springframework.util.ReflectionUtils.findField(Pedido.class, fieldName);
            campoEntidad.setAccessible(true);
            if (fieldName.equals("precio")){
                fieldValue= new BigDecimal (field.getValue().toString());
            }else if (fieldName.equals("creado")){
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm");
                fieldValue = LocalDateTime.parse(field.getValue().toString(),formatter);
            }else if (fieldName.equals("detalle")){
                List<?> originalList = mapper.convertValue(fields.get(fieldName), new TypeReference<List<?>>() {});
                try {
                  Class<?> type = Class.forName("pedidos.pedidos.core.pedidos.DetallePedido");
                  List<Object> newList = new java.util.ArrayList<>();
                  for (Object o : originalList) {
                    newList.add(mapper.convertValue(o, type));
                  }
                  campoEntidad.set(entity,newList);
                } catch(ClassNotFoundException ex) {
                  System.out.println("Error occuured");
                  ex.printStackTrace();
                } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }else {
                fieldValue =field.getValue();
            }

            // utiliza reflection para establecer el valor del campo en la entidad
            try {
                //Field campoEntidad = Pedido.class.getDeclaredField(fieldName);


                if (campoEntidad.isAnnotationPresent(ManyToOne.class)) {
                    java.util.LinkedHashMap<String, Long> keyValue = mapper.convertValue(fieldValue, new TypeReference<java.util.LinkedHashMap<String, Long>>(){});
                    Object relatedEntity = clienteService.findById(keyValue.get("id"));
                    campoEntidad.set(entity, relatedEntity);
                } if (campoEntidad.isAnnotationPresent(OneToMany.class)) {
                    //java.util.LinkedHashMap<String, Long> keyValue = mapper.convertValue(fieldValue, new TypeReference<java.util.LinkedHashMap<String, Long>>(){});
                    //Object relatedEntity = entidadService.findById(keyValue.get("id"));
                    //campoEntidad.set(entity, relatedEntity);
                }
                else{
                    //campoEntidad.set(entity, fieldValue);
                    campoEntidad.set(entity, mapper.convertValue(fieldValue, campoEntidad.getType()));
                }

                
            } catch ( IllegalAccessException ex) {
                // maneja la excepción si ocurre algún error al acceder al campo
            }
        }
        return update(entity);
    }

}	
