package tmobile

import (
	"context"
	"fmt"
)

type MockClientAccTokResSucc struct {
	*TMobClient
	wasSet      chan string
	n           uint8
	iccidFilter ICCIDFilter
}

var _ TMobClienter = &MockClientAccTokResSucc{}

func (mc *MockClientAccTokResSucc) Details(ctx context.Context, ID string) (out *SMSDetailsResponse, err error) {
	//TODO implement me
	panic("implement me")
}

var mockAccessTokenResponse = &AccessTokenResponse{
	IdToken:     "accessToken",
	AccessToken: "accessToken",
	ExpiresIn:   2,
	TokenType:   "tokenType",
	Resource:    "resource",
	Scope:       "scope",
}

func (mc *MockClientAccTokResSucc) AccessToken(
	ctx context.Context,
) (out *AccessTokenResponse, err error) {
	matr := *mockAccessTokenResponse

	matr.AccessToken = fmt.Sprintf("accessToken%d", mc.n)

	if mc.n == 1 {
		matr.ExpiresIn = 6
		return &matr, nil
	}

	mc.n++
	return &matr, nil
}

func (mc *MockClientAccTokResSucc) SetAccessToken(
	accessToken string,
) {
	mc.wasSet <- accessToken
}

// SetFilter implements TMobClienter.
func (mc *MockClientAccTokResSucc) SetFilter(filter []string) {
	mc.iccidFilter = ICCIDFilter{
		filter: filter,
	}
}

type MockClientAccTokResFail struct {
	TMobClienter
	wasSet chan struct{}
}

func (mc *MockClientAccTokResFail) AccessToken(
	ctx context.Context,
) (out *AccessTokenResponse, err error) {
	mc.wasSet <- struct{}{}
	return nil, fmt.Errorf("failed to get access token")
}

type MockClientSendSMSResFail struct {
	TMobClienter
	wasSet chan struct{}
}

func (mc *MockClientSendSMSResFail) SendSMS(
	ctx context.Context,
	req *SendSMSRequest,
) (out *SendSMSResponse, err error) {
	mc.wasSet <- struct{}{}
	return nil, fmt.Errorf("failed to send SMS")
}

type MockClientSendSMSExpire struct {
	TMobClienter
}

func (mc *MockClientSendSMSExpire) SendSMS(
	ctx context.Context,
	req *SendSMSRequest,
) (out *SendSMSResponse, err error) {
	return &SendSMSResponse{
		SmsMessageID: "smsMessageID",
	}, nil
}

func (mc *MockClientSendSMSExpire) Details(
	ctx context.Context,
	ID string,
) (out *SMSDetailsResponse, err error) {
	return &SMSDetailsResponse{
		SmsMsgID: "smsMessageID",
		Status:   Pending,
	}, nil
}

type MockClientSendSMSDetailsFailRes struct {
	TMobClienter
	wasSet chan struct{}
}

func (mc *MockClientSendSMSDetailsFailRes) SendSMS(
	ctx context.Context,
	in *SendSMSRequest,
) (out *SendSMSResponse, err error) {
	return &SendSMSResponse{
		SmsMessageID: "smsMessageID",
	}, nil
}

func (mc *MockClientSendSMSDetailsFailRes) Details(
	ctx context.Context,
	ID string,
) (out *SMSDetailsResponse, err error) {
	mc.wasSet <- struct{}{}
	return nil, fmt.Errorf("failed to get SMS details")
}

type MockClientSendSMSDetailsFailWithBadStatus struct {
	TMobClienter
	wasSet chan SmsDetailsStatus
	toFail []SmsDetailsStatus
	n      uint8
}

func (mc *MockClientSendSMSDetailsFailWithBadStatus) SendSMS(
	ctx context.Context,
	in *SendSMSRequest,
) (out *SendSMSResponse, err error) {
	return &SendSMSResponse{
		SmsMessageID: "smsMessageID",
	}, nil
}

func (mc *MockClientSendSMSDetailsFailWithBadStatus) Details(
	ctx context.Context,
	ID string,
) (out *SMSDetailsResponse, err error) {
	status := mc.toFail[mc.n]
	mc.wasSet <- status
	mc.n++

	return &SMSDetailsResponse{
		SmsMsgID: "smsMessageID",
		Status:   status,
	}, nil
}

type MockClientSendSMSResSucc struct {
	TMobClienter
	wasSet chan SmsDetailsStatus
	n      uint8
}

func (mc *MockClientSendSMSResSucc) SendSMS(
	ctx context.Context,
	in *SendSMSRequest,
) (out *SendSMSResponse, err error) {
	return &SendSMSResponse{
		SmsMessageID: "smsMessageID",
	}, nil
}

var smsStatusInitialStages = []SmsDetailsStatus{
	Pending,
	CancelPending,
}

var smsStatusSuccStages = append(smsStatusInitialStages, Delivered)

var smsStatusFailTypes = [][]SmsDetailsStatus{
	append(smsStatusInitialStages, Failed),
	append([]SmsDetailsStatus{}, Cancelled),
	append([]SmsDetailsStatus{}, Received),
	append([]SmsDetailsStatus{}, Unknown),
	append([]SmsDetailsStatus{}, CancelFailed),
}

func (mc *MockClientSendSMSResSucc) Details(ctx context.Context, ID string) (out *SMSDetailsResponse, err error) {
	status := smsStatusSuccStages[mc.n]
	mc.wasSet <- status
	mc.n++

	return &SMSDetailsResponse{
		SmsMsgID: "smsMessageID",
		Status:   status,
	}, nil
}

