package tmobile

import (
	"strconv"
	"strings"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/grpc/sms"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/utils/envtool"
)

var FISKER_TMOBILE_ACCOUNT_ID = envtool.GetEnv("FISKER_TMOBILE_ACCOUNT_ID", "500556839")

type AccessTokenResponse struct {
	IdToken      string `json:"id_token"`
	AccessToken  string `json:"access_token"`
	ExpiresIn    int    `json:"expires_in"`
	TokenType    string `json:"token_type"`
	Resource     string `json:"resource"`
	RefreshToken string `json:"refresh_token"`
	Scope        string `json:"scope"`
}

type SendSMSRequest struct {
	// An array of ICCIDs or MSISDNs that you want to send the message to. At least one item is required.
	// Please note the pluralized property name. Maximum length is 50.
	ICCID string `json:"iccid,omitempty" validate:"required,iccid,lte=50"`

	MSISDN *string `json:"msisdn,omitempty" validate:"omitempty,lte=50"`

	// If the API does not specify the data coding type, the default maximum message length is 320
	// characters. Messages that exceed 160 characters appear on two lines.
	MessageText string `json:"messageText,omitempty" validate:"required,lte=320"`

	// (Optional) The type of message encoding used. Valid values are LITERAL (default) or BASE64.
	MessageEncoding *string `json:"messageEncoding,omitempty" validate:"omitempty,oneof=LITERAL BASE64"`

	// (Optional) The type of data encoding used.
	// 0 - SMSC default alphabet; often GSM encoding
	// 1 - IA5/ASCII (but sometimes GSM depending on the SMSC implementation)
	// 3 - Latin 1 (ISO-8859-1)
	// 4 - Binary SMS
	// 8 - Unicode UCS2
	DataCoding *string `json:"dataCoding,omitempty" validate:"omitempty,oneof=0 1 3 4 8"`

	// (Optional) The length of time the message is available before expiring.
	// The default value is 0.
	// 0 – 143   | (TPVP + 1) x 5 minutes         | 5, 10, 15 minutes ... 11:55, 12:00 hours
	// 144 - 167 | (12 + (TPVP - 143) / 2) hours  | 12:30, 13:00, ... 23:30, 24:00 hours
	// 168 - 196 | (TPVP - 166) days              | 2, 3, 4, ... 30 days
	// 197 - 255 | (TPVP - 192) weeks             | 5, 6, 7, ... 63 weeks
	TPVP *string `json:"tpvp,omitempty" validate:"omitempty,numeric,min=0,max=255"`

	KafkaServiceTarget string `json:"kafkaServiceTarget,omitempty"`

	await bool
}

func (r *SendSMSRequest) Await() bool {
	return r.await
}

func (r *SendSMSRequest) FromProtobuf(setReq *sms.SendSMSRequest) {
	r.ICCID = setReq.ICCID

	r.ICCID = strings.TrimSuffix(strings.ToLower(r.ICCID), "f")

	r.MessageText = setReq.MessageText
	if setReq.MessageEncoding != nil {
		encoding := setReq.MessageEncoding.String()
		r.MessageEncoding = &encoding
	}

	if setReq.DataCoding != nil {
		dc := strconv.Itoa(int(setReq.DataCoding.Enum().Number()))
		r.DataCoding = &dc
	}

	r.TPVP = setReq.Tpvp
	r.await = setReq.Await
}

const tpvpUnit = 5 * time.Minute

var minAwait time.Duration

func init() {
	def := time.Second * 10
	ma, err := time.ParseDuration(envtool.GetEnv("SMS_MIN_AWAIT", "10s"))
	if err != nil {
		logger.Warn().Err(err).Msgf("SMS_MIN_AWAIT not set, setting default %v", def)
		ma = def
	}

	minAwait = ma
}

func (r *SendSMSRequest) ExpireIfNotDelivered() (exp time.Duration) {
	return time.Millisecond * 300
	/* if r.TPVP == nil {
		r.TPVP = new(string)
		*r.TPVP, exp = deftpvp()

		return
	}

	num, err := strconv.Atoi(*r.TPVP)
	if err != nil {
		*r.TPVP, exp = deftpvp()

		return
	}

	if num > 255 {
		*r.TPVP, exp = maxtpvp()

		return
	} else if num < 0 {
		*r.TPVP, exp = deftpvp()

		return
	}

	return time.Duration(num) * tpvpUnit */
}

type SendSMSResponse struct {
	SmsMessageID string `json:"smsMessageId"`
}

type SmsDetailsStatus string

const (
	Received      SmsDetailsStatus = "Received"
	Cancelled     SmsDetailsStatus = "Cancelled"
	CancelFailed  SmsDetailsStatus = "CancelFailed"
	CancelPending SmsDetailsStatus = "CancelPending"
	Delivered     SmsDetailsStatus = "Delivered"
	Pending       SmsDetailsStatus = "Pending"
	Failed        SmsDetailsStatus = "Failed"
	Unknown       SmsDetailsStatus = "Unknown"
)

type SMSDetailsResponse struct {
	SmsMsgID     string           `json:"smsMsgId"`
	Status       SmsDetailsStatus `json:"status"`
	MessageText  string           `json:"messageText"`
	SenderLogin  string           `json:"senderLogin"`
	SentTo       string           `json:"sentTo"`
	SentFrom     string           `json:"sentFrom"`
	MsgType      string           `json:"msgType"`
	DateSent     string           `json:"dateSent"`
	DateModified string           `json:"dateModified"`
	ICCID        string           `json:"iccid"`
}

func (r *SMSDetailsResponse) ToProtobuf() *sms.SMSDetailsResponse {
	status := sms.SMSDetailsResponse_Status(
		sms.SMSDetailsResponse_Status_value[string(r.Status)])

	return &sms.SMSDetailsResponse{
		SmsMsgID:     r.SmsMsgID,
		Status:       status,
		MessageText:  r.MessageText,
		SenderLogin:  r.SenderLogin,
		SentTo:       r.SentTo,
		SentFrom:     r.SentFrom,
		MsgType:      r.MsgType,
		DateSent:     r.DateSent,
		DateModified: r.DateModified,
		ICCID:        r.ICCID,
	}
}

type ChangeRatePlanRequest struct {
	ICCID     string `json:"iccid,omitempty" validate:"required,iccid,lte=50"`
	ProductId string `json:"productId,omitempty" validate:"required"`
	AccountId string `json:"accountId,omitempty" validate:"required"`
}

func (r *ChangeRatePlanRequest) FromProtobuf(req *sms.ChangeRatePlanRequest) {
	r.ICCID = strings.TrimSuffix(strings.ToLower(req.ICCID), "f")
	r.ProductId = req.ProductId
	r.AccountId = req.AccountId
}

type ChangeRatePlanResponse struct {
	ICCID string `json:"iccid,omitempty"`
}

type CustomAtributesRequest struct {
	ICCID          string `json:"iccid,omitempty" validate:"required,iccid,lte=50"`
	AccountCustom1 string `json:"accountCustom1,omitempty" validate:"required"`
}

func (r *CustomAtributesRequest) FromProtobuf(req *sms.CustomAtributesRequest) {
	r.ICCID = strings.TrimSuffix(strings.ToLower(req.ICCID), "f")
	r.AccountCustom1 = req.AccountCustom1
}

type CustomAtributesResponse struct {
	ICCID string `json:"iccid,omitempty"`
}

type DeviceDetailsRequest struct {
	ICCID string `json:"iccid,omitempty" validate:"required,iccid,lte=50"`
}

type ICCIDBody struct {
	ICCID string `json:"iccid,omitempty" validate:"required,iccid,lte=50"`
}

type DeviceDetailsResponse struct {
	ICCID          string `json:"iccid,omitempty"`
	RatePlan       string `json:"ratePlan,omitempty"`
	AccountId      string `json:"accountId,omitempty"`
	AccountCustom1 string `json:"accountCustom1,omitempty"`
	Status         string `json:"status,omitempty"`
}

func (ddr *DeviceDetailsResponse) ToProtobuf() *sms.DeviceDetailsResponse {
	res := &sms.DeviceDetailsResponse{
		ICCID:          ddr.ICCID,
		RatePlan:       ddr.RatePlan,
		AccountId:      ddr.AccountId,
		AccountCustom1: ddr.AccountCustom1,
		Status:         ddr.Status,
	}
	return res
}

type SMSQueueResponse struct {
	SmsMsgID       string `json:"smsMsgId"`
	SentSuccessful bool   `json:"sentSuccessful"`
}

func (sqr *SMSQueueResponse) ToProtobuf() *sms.SMSQueueResponse {
	res := &sms.SMSQueueResponse{
		SmsMsgID:       sqr.SmsMsgID,
		SentSuccessful: sqr.SentSuccessful,
	}
	return res
}


type ChangeDeviceActivation struct {
	ICCIDs []string
	Enabled bool
}