package client

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"

	"git.espin.casa/albert/cml04-mediciones/internal/types"
)

type IMediciones interface {
	// production orders from SAP
	GetProductionOrder(ctx context.Context, req types.GetProductionOrderReq) (res types.GetProductionOrderRes, err error)
	GetProductionOrders(ctx context.Context, req types.GetProductionOrdersReq) (res types.GetProductionOrdersRes, err error)
	// mediciones
	GetMedicion(ctx context.Context, req types.GetMedicionReq) (res types.GetMedicionRes, err error)
	GetMediciones(ctx context.Context, req types.GetMedicionesReq) (res types.GetMedicionesRes, err error)
	PostMediciones(ctx context.Context, req types.PostMedicionesReq) (res types.PostMedicionesRes, err error)
	// ususarios
	GetUsuario(ctx context.Context, req types.GetUsuarioReq) (res types.GetUsuarioRes, err error)
	CreateUsuario(ctx context.Context, req types.CreateUsuarioReq) (res types.CreateUsuarioRes, err error)
	ValidarUsuario(ctx context.Context, req types.ValidarUsuarioReq) (res types.ValidarUsuarioRes, err error)
	// tolerancias
	GetTolerancia(ctx context.Context, req types.GetToleranciaReq) (res types.GetToleranciaRes, err error)
	// datos excel
	GetExcelData(ctx context.Context, req types.GetExcelReq) (res types.GetExcelRes, err error)
}

type client struct {
	url string
}

// GetExcelData implements IMediciones.
func (c client) GetExcelData(ctx context.Context, req types.GetExcelReq) (res types.GetExcelRes, err error) {
	// encode request
	data, err := json.Marshal(req)
	if err != nil {
		return types.GetExcelRes{}, err
	}
	resp, err := http.Post(c.url+"/excel/get", "application/json", bytes.NewBuffer(data))
	if err != nil {
		return types.GetExcelRes{}, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return types.GetExcelRes{}, err
	}
	if err := json.Unmarshal(body, &res); err != nil {
		return types.GetExcelRes{}, err
	}
	return
}

// GetTolerancia implements IMediciones.
func (c client) GetTolerancia(ctx context.Context, req types.GetToleranciaReq) (res types.GetToleranciaRes, err error) {
	// encode request
	data, err := json.Marshal(req)
	if err != nil {
		return types.GetToleranciaRes{}, err
	}
	resp, err := http.Post(c.url+"/tolerance", "application/json", bytes.NewBuffer(data))
	if err != nil {
		return types.GetToleranciaRes{}, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return types.GetToleranciaRes{}, err
	}
	if err := json.Unmarshal(body, &res); err != nil {
		return types.GetToleranciaRes{}, err
	}
	return
}

// CreateUsuario implements IMediciones.
func (c client) CreateUsuario(ctx context.Context, req types.CreateUsuarioReq) (types.CreateUsuarioRes, error) {
	panic("unimplemented")
}

// GetMedicion implements IMediciones.
func (c client) GetMedicion(ctx context.Context, req types.GetMedicionReq) (types.GetMedicionRes, error) {
	panic("unimplemented")
}

// GetMediciones implements IMediciones.
func (c client) GetMediciones(ctx context.Context, req types.GetMedicionesReq) (res types.GetMedicionesRes, err error) {
	// encode request
	data, err := json.Marshal(req)
	if err != nil {
		return types.GetMedicionesRes{}, err
	}
	resp, err := http.Post(c.url+"/mediciones", "application/json", bytes.NewBuffer(data))
	if err != nil {
		return types.GetMedicionesRes{}, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return types.GetMedicionesRes{}, err
	}
	if err := json.Unmarshal(body, &res); err != nil {
		return types.GetMedicionesRes{}, err
	}
	return
}

// GetProductionOrder implements IMediciones.
func (c client) GetProductionOrder(ctx context.Context, req types.GetProductionOrderReq) (res types.GetProductionOrderRes, err error) {
	data, err := json.Marshal(req)
	if err != nil {
		return types.GetProductionOrderRes{}, err
	}
	resp, err := http.Post(c.url+"/po", "application/json", bytes.NewBuffer(data))
	if err != nil {
		return types.GetProductionOrderRes{}, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return types.GetProductionOrderRes{}, err
	}
	if err := json.Unmarshal(body, &res); err != nil {
		return types.GetProductionOrderRes{}, err
	}
	return
}

// GetProductionOrders implements IMediciones.
func (c client) GetProductionOrders(ctx context.Context, req types.GetProductionOrdersReq) (res types.GetProductionOrdersRes, err error) {
	// encode request
	data, err := json.Marshal(req)
	if err != nil {
		return types.GetProductionOrdersRes{}, err
	}
	resp, err := http.Post(c.url+"/pos", "application/json", bytes.NewBuffer(data))
	if err != nil {
		return types.GetProductionOrdersRes{}, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return types.GetProductionOrdersRes{}, err
	}
	if err := json.Unmarshal(body, &res); err != nil {
		return types.GetProductionOrdersRes{}, err
	}
	return
}

// GetUsuario implements IMediciones.
func (c client) GetUsuario(ctx context.Context, req types.GetUsuarioReq) (res types.GetUsuarioRes, err error) {
	panic("unimplemented")
}

// PostMediciones implements IMediciones.
func (c client) PostMediciones(ctx context.Context, req types.PostMedicionesReq) (res types.PostMedicionesRes, err error) {
	// encode request
	data, err := json.Marshal(req)
	if err != nil {
		return types.PostMedicionesRes{}, err
	}
	resp, err := http.Post(c.url+"/medicion/create", "application/json", bytes.NewBuffer(data))
	if err != nil {
		return types.PostMedicionesRes{}, err
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return types.PostMedicionesRes{}, err
	}
	if err := json.Unmarshal(body, &res); err != nil {
		return types.PostMedicionesRes{}, err
	}
	return

}

// ValidarUsuario implements IMediciones.
func (c client) ValidarUsuario(ctx context.Context, req types.ValidarUsuarioReq) (types.ValidarUsuarioRes, error) {
	panic("unimplemented")
}

type ClientConfig struct {
	Host string
	Port int
	Base string
}

func NewClient(conf *ClientConfig) IMediciones {
	url := fmt.Sprintf("http://%s:%d/%s", conf.Host, conf.Port, conf.Base)
	return client{
		url: url,
	}
}
