package pedidos.pedidos.core.cliente;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.PatchMapping;
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.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.core.type.TypeReference;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.persistence.ManyToOne;
import pedidos.pedidos.core.compania.CompaniaService;

import java.util.List;
import java.lang.reflect.Field;
import java.util.Map;

@RestController
@RequestMapping("api/cliente")
@CrossOrigin({"*"})
@Tag(name = "Controlador de Cliente (Tabla cliente)")
public class ClienteController {
    @Autowired ClienteService clienteService;
    @Autowired CompaniaService companiaService;

    @PreAuthorize("hasAuthority('Cliente_LeerTodos')")
    @GetMapping("/")
    @Operation(summary = "Obtiene todos los clientes, requiere el permiso Cliente_LeerTodos ")
    public List<Cliente> findAll(){
        return clienteService.findAll();
    }

    @GetMapping("/{id}/")
    public Cliente findById(@PathVariable long id){
        return clienteService.findById(id);
    }

    @PostMapping("/")
    @PreAuthorize("hasAuthority('Cliente_Crear')")
    public Cliente save(@RequestBody Cliente entity){
        return clienteService.save(entity);
    }

    @PutMapping("/{id}/")
    public Cliente update(@RequestBody Cliente entity){
        return clienteService.save(entity);
    }

    @DeleteMapping("/{id}/")
    public void deleteById(@PathVariable long id){
        clienteService.deleteById(id);
    }

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

        Cliente cliente = findById(id);

        // itera sobre los campos que se desean actualizar
        for (Map.Entry<String, Object> field : fields.entrySet()) {
            String fieldName = field.getKey();
            Object fieldValue = field.getValue();
            
            // utiliza reflection para establecer el valor del campo en la entidad
            try {
                ObjectMapper mapper = new ObjectMapper();
                mapper.registerModule(new JavaTimeModule());
                Field campoEntidad = Cliente.class.getDeclaredField(fieldName);
                campoEntidad.setAccessible(true);

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

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