package usecase

import (
	errs "backend/pkg/library/errors"
	"bytes"
	"context"
	"encoding/json"
	"io"
	"net/http"
	"net/url"

	"backend/pkg/member/domain/usecase"
)

// LineCodeToAccessToken 透過 Line 授權碼換取 Access Token
func (use *MemberUseCase) LineCodeToAccessToken(ctx context.Context, code string) (usecase.LineAccessTokenResponse, error) {
	data := url.Values{
		"grant_type":    {"authorization_code"},
		"code":          {code},
		"redirect_uri":  {use.Config.LineAuth.RedirectURI},
		"client_id":     {use.Config.LineAuth.ClientID},
		"client_secret": {use.Config.LineAuth.ClientSecret},
	}

	uri := "https://api.line.me/oauth2/v2.1/token"
	headers := map[string]string{
		"Content-Type": "application/x-www-form-urlencoded",
	}

	var tokenResponse usecase.LineAccessTokenResponse
	if err := use.doPost(ctx, uri, headers, data.Encode(), &tokenResponse); err != nil {
		return usecase.LineAccessTokenResponse{}, err
	}

	return tokenResponse, nil
}

// LineGetProfileByAccessToken 使用 Access Token 獲取 Line 用戶資料
func (use *MemberUseCase) LineGetProfileByAccessToken(ctx context.Context, accessToken string) (*usecase.LineUserProfile, error) {
	uri := "https://api.line.me/v2/profile"
	headers := map[string]string{
		"Authorization": "Bearer " + accessToken,
	}

	var profile usecase.LineUserProfile
	if err := use.doGet(ctx, uri, headers, &profile); err != nil {
		return nil, err
	}

	return &profile, nil
}

// doPost 發送 POST 請求並解析返回數據
func (use *MemberUseCase) doPost(ctx context.Context, uri string, headers map[string]string, body string, result interface{}) error {
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, bytes.NewBufferString(body))
	if err != nil {
		return errs.SvcThirdPartyErrorL(
			use.Logger,
			[]errs.LogField{
				{Key: "uri", Val: uri},
				{Key: "headers", Val: headers},
				{Key: "body", Val: body},
				{Key: "result", Val: result},
				{Key: "method", Val: http.MethodPost},
			},
			"failed to create request")
	}
	for key, value := range headers {
		req.Header.Set(key, value)
	}

	return use.doRequest(req, result)
}

// doGet 發送 GET 請求並解析返回數據
func (use *MemberUseCase) doGet(ctx context.Context, uri string, headers map[string]string, result interface{}) error {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
	if err != nil {
		return errs.SvcThirdPartyErrorL(
			use.Logger,
			[]errs.LogField{
				{Key: "uri", Val: uri},
				{Key: "headers", Val: headers},
				{Key: "result", Val: result},
				{Key: "method", Val: http.MethodGet},
			},
			"failed to create request")
	}
	for key, value := range headers {
		req.Header.Set(key, value)
	}

	return use.doRequest(req, result)
}

// doRequest 發送 HTTP 請求並處理響應
func (use *MemberUseCase) doRequest(req *http.Request, result interface{}) error {
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return errs.SvcThirdPartyErrorL(
			use.Logger,
			[]errs.LogField{
				{Key: "req", Val: req},
				{Key: "result", Val: result},
				{Key: "method", Val: http.MethodGet},
			},
			"failed to create request")
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return errs.SvcThirdPartyError("unexpected status code: " + http.StatusText(resp.StatusCode))
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return errs.SvcThirdPartyError("failed to read response body")
	}

	if err := json.Unmarshal(body, result); err != nil {
		return errs.SvcThirdPartyError("failed to parse response body")
	}

	return nil
}
