package service

import (
	"baron-sso-backend/internal/domain"
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log/slog"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type SmsServiceImpl struct {
	accessKey   string
	secretKey   string
	serviceID   string
	senderPhone string
}

func NewSmsService() domain.SmsService {
	// Sanitize sender phone number right after reading from env
	rawSenderPhone := os.Getenv("NAVER_SENDER_PHONE_NUMBER")
	sanitizedSenderPhone := strings.ReplaceAll(rawSenderPhone, "-", "")
	slog.Info("[서비스 초기화] 발신자 번호 처리", "원본", rawSenderPhone, "정제후", sanitizedSenderPhone)

	return &SmsServiceImpl{
		accessKey:   os.Getenv("NAVER_CLOUD_ACCESS_KEY"),
		secretKey:   os.Getenv("NAVER_CLOUD_SECRET_KEY"),
		serviceID:   os.Getenv("NAVER_CLOUD_SERVICE_ID"),
		senderPhone: sanitizedSenderPhone,
	}
}

func (s *SmsServiceImpl) SendSms(to, content string) error {
	timestamp := strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)
	apiURL := fmt.Sprintf("https://sens.apigw.ntruss.com/sms/v2/services/%s/messages", s.serviceID)
	slog.Info("[SmsService] Requesting SENS API URL", "url", apiURL)

	// Naver SENS API requires phone number without '+'
	sanitizedTo := strings.Replace(to, "+", "", 1)

	reqBody := domain.NaverSmsRequest{
		Type:        "SMS",
		ContentType: "COMM",
		CountryCode: "82",
		From:        s.senderPhone,
		Content:     content,
		Messages: []domain.SmsMessage{
			{
				To: sanitizedTo,
			},
		},
	}

	jsonBody, err := json.Marshal(reqBody)
	if err != nil {
		return fmt.Errorf("error marshalling request body: %w", err)
	}

	signature, err := s.makeSignature("POST", fmt.Sprintf("/sms/v2/services/%s/messages", s.serviceID), timestamp)
	if err != nil {
		return fmt.Errorf("error creating signature: %w", err)
	}

	req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBody))
	if err != nil {
		return fmt.Errorf("error creating request: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-ncp-apigw-timestamp", timestamp)
	req.Header.Set("x-ncp-iam-access-key", s.accessKey)
	req.Header.Set("x-ncp-apigw-signature-v2", signature)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("error sending request: %w", err)
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("error reading response body: %w", err)
	}

	if resp.StatusCode >= 300 {
		slog.Error("[SmsService] error response from naver cloud sms api", "body", string(respBody))
		return fmt.Errorf("error sending sms: status code %d", resp.StatusCode)
	}

	slog.Info("[SmsService] sms sent successfully", "body", string(respBody))
	return nil
}

func (s *SmsServiceImpl) makeSignature(method, url, timestamp string) (string, error) {
	space := " "
	newLine := "\n"
	message := method + space + url + newLine + timestamp + newLine + s.accessKey

	h := hmac.New(sha256.New, []byte(s.secretKey))
	_, err := h.Write([]byte(message))
	if err != nil {
		return "", err
	}

	return base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
}
