package verify

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

	"bsm/full/module/base/passport/internal/config"
	"bsm/full/module/base/passport/internal/impl"
	"bsm/full/module/base/passport/internal/logic/common"
	"bsm/full/module/base/passport/internal/models"
	pb "bsm/full/module/base/passport/pb"
	"git.apinb.com/bsm-sdk/core/errcode"
	"git.apinb.com/bsm-sdk/core/printer"
	"git.apinb.com/bsm-sdk/core/service"
)

type JumioInitRequest struct {
	CustomerInternalReference string `json:"customerInternalReference"`
	UserReference             string `json:"userReference"`
	SuccessURL                string `json:"successUrl"`
	ErrorURL                  string `json:"errorUrl"`
	CallbackURL               string `json:"callbackUrl"`
}

type JumioInitResponse struct {
	Timestamp         string `json:"timestamp"`
	ScanReference     string `json:"scanReference"`
	ClientRedirectURL string `json:"clientRedirectUrl"`
}

func Request(ctx context.Context, in *pb.VerifyRequest) (reply *pb.StatusReply, err error) {
	auth, err := service.ParseMetaCtx(ctx, nil)
	if err != nil {
		return nil, err
	}

	var data string
	switch strings.ToLower(in.Provider) {
	case "jumio":
		id := fmt.Sprintf("ID_%d", auth.ID)
		resp, err := InitiateJumioScan(id, auth.Identity)
		if err != nil {
			printer.Error(err.Error())
			return nil, errcode.ErrInternal
		}
		data = resp.ClientRedirectURL
	case "local":
		if !common.VerifyMapKeys(in.Args, []string{"type", "name", "number", "front", "back"}) {
			return nil, errcode.ErrInvalidArgument
		}
		err = LocalVerify(auth.ID, in.Args)
		if err != nil {
			printer.Error(err.Error())
			return nil, errcode.ErrDB
		}
	default:
		return nil, errcode.ErrNotFound(404, "provider")
	}

	return &pb.StatusReply{
		Details: data,
		Timeseq: time.Now().UnixMilli(),
	}, nil
}

func LocalVerify(authID uint, args map[string]string) error {
	err := impl.DBService.Model(&models.PassportData{}).Where("passport_id = ?", authID).Update("document_verify", 1).Error
	if err != nil {
		return err
	}

	err = impl.DBService.Model(&models.PassportVerify{}).Where("passport_id = ?", authID).Updates(map[string]any{
		"document_verify_at": time.Now(),
		"document_type":      args["type"],
		"document_name":      args["name"],
		"document_number":    args["number"],
		"document_front":     args["front"],
		"document_back":      args["back"],
	}).Error
	if err != nil {
		return err
	}
	return nil
}

func InitiateJumioScan(internalRef, userRef string) (*JumioInitResponse, error) {
	if config.Spec.Kyc == nil {
		return nil, fmt.Errorf("kyc config is missing")
	}

	reqBody := JumioInitRequest{
		CustomerInternalReference: internalRef,
		UserReference:             userRef,
		CallbackURL:               config.Spec.Kyc.ApiArgs,
	}

	jsonBody, err := json.Marshal(reqBody)
	if err != nil {
		return nil, err
	}

	client := &http.Client{Timeout: 10 * time.Second}
	req, err := http.NewRequest(http.MethodPost, config.Spec.Kyc.BaseUrl, bytes.NewBuffer(jsonBody))
	if err != nil {
		return nil, err
	}

	req.SetBasicAuth(config.Spec.Kyc.ApiToken, config.Spec.Kyc.ApiSecret)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "BSM-Passport/1.0")

	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("jumio api error: status=%d body=%s", resp.StatusCode, string(body))
	}

	var jumioResp JumioInitResponse
	err = json.Unmarshal(body, &jumioResp)
	if err != nil {
		return nil, err
	}

	return &jumioResp, nil
}
