package pdu

import (
	"bytes"
	"encoding/binary"
	"fmt"

	"smpptester/encoding"
)

type (
	SUBMIT_SM struct {
		Header                 *PDU_HEADER
		Service_type           string
		Source_addr_ton        byte
		Source_addr_npi        byte
		Source_addr            string
		Dest_addr_ton          byte
		Dest_addr_npi          byte
		Destination_addr       string
		Esm_class              byte
		Protocol_id            byte
		Priority_flag          byte
		Schedule_delivery_time string
		Validity_period        string
		Registered_delivery    byte
		Replace_if_present     byte
		Data_coding            byte
		Sm_default_msg_id      byte
		Sm_length              byte
		Short_message          string
		// user_message_reference uint16
		// source_port               uint16
		// source_addr_subunit       byte
		// destination_port          uint16
		// dest_addr_subunit         byte
		// sar_msg_ref_num           uint16
		// sar_total_segments        byte
		// sar_segment_seqnum        byte
		// more_messages_to_send     byte
		// payload_type              byte
		// message_payload           string
		// privacy_indicator         byte
		// callback_num              string
		// callback_num_pres         byte
		// callback_num_atag         string
		// source_subaddress         string
		// dest_subaddress           string
		// user_response_code        byte
		// display_time              byte
		// sms_signal                byte
		// ms_validity               byte
		// ms_msg_wait_facilities    byte
		// number_of_messages        byte
		// alert_on_message_delivery byte
		// language_indicator        byte
		// its_reply_type            byte
		// its_session_info          byte
		// ussd_service_op           byte
	}
	SUBMIT_SM_RESP struct {
		Header     *PDU_HEADER
		Message_id string
	}
	SUBMIT_MULTI      struct{}
	SUBMIT_MULTI_RESP struct{}
)

// See https://www.codeproject.com/Tips/470755/Encoding-Decoding-7-bit-User-Data-for-SMS-PDU-PDU
// Another great site: https://doubleblak.com/blogPost.php?k=7bitpdu

func (p *SUBMIT_SM) Encode(buf *bytes.Buffer) error {
	if buf == nil {
		return fmt.Errorf("cannot encode into nil buffer")
	}
	messageEncoder := p.GetEncoder()

	p.Header.Encode(buf)
	// These should be ASCII but UTF8 is a superset of ASCII so hopefully this'll be fine
	buf.WriteString(p.Service_type)
	buf.Write(NULL_ARR)
	binary.Write(buf, binary.BigEndian, p.Source_addr_ton)
	binary.Write(buf, binary.BigEndian, p.Source_addr_npi)
	buf.WriteString(p.Source_addr)
	buf.Write(NULL_ARR)
	binary.Write(buf, binary.BigEndian, p.Dest_addr_ton)
	binary.Write(buf, binary.BigEndian, p.Dest_addr_npi)
	buf.WriteString(p.Destination_addr)
	buf.Write(NULL_ARR)
	binary.Write(buf, binary.BigEndian, p.Esm_class)
	binary.Write(buf, binary.BigEndian, p.Protocol_id)
	binary.Write(buf, binary.BigEndian, p.Priority_flag)
	buf.WriteString(p.Schedule_delivery_time)
	buf.Write(NULL_ARR)
	buf.WriteString(p.Validity_period)
	buf.Write(NULL_ARR)
	binary.Write(buf, binary.BigEndian, p.Registered_delivery)
	binary.Write(buf, binary.BigEndian, p.Replace_if_present)
	binary.Write(buf, binary.BigEndian, p.Data_coding)
	binary.Write(buf, binary.BigEndian, p.Sm_default_msg_id)
	binary.Write(buf, binary.BigEndian, p.Sm_length)
	err := messageEncoder.Encode(&p.Short_message, buf)
	if err != nil {
		return err
	}
	return nil
}
func (p *SUBMIT_SM) Decode(buf *bytes.Buffer) error {
	if buf == nil {
		return fmt.Errorf("cannot decode nil buffer")
	}
	return nil
}
func (p *SUBMIT_SM) Size() int {
	var size int
	size += p.Header.Size()
	size += 1 + len(p.Service_type)
	size += 1 // source_addr_ton
	size += 1 // source_addr_npi
	size += 1 + len(p.Source_addr)
	size += 1 // dest_addr_ton
	size += 1 // dest_addr_npi
	size += 1 + len(p.Destination_addr)
	size += 1 // esm_class
	size += 1 // protocol_id
	size += 1 // priority_flag
	size += 1 + len(p.Schedule_delivery_time)
	size += 1 + len(p.Validity_period)
	size += 1 // registered_delivery
	size += 1 // replace_if_present
	size += 1 // data_coding
	size += 1 // sm_default_msg_id
	size += 1 // sm_length
	size += p.GetEncoder().EncodesInto(&p.Short_message)
	return size
}
func (p *SUBMIT_SM) UpdateSize() {
	p.Header.Command_length = uint32(p.Size())
	p.Sm_length = byte(p.GetEncoder().EncodesInto(&p.Short_message))
}
func (p *SUBMIT_SM) GetEncoder() encoding.Coder {
	switch p.Data_coding {
	case 0b00000000: // GSM7
		return &encoding.GSM7Coder{}
	case 0b00000001: // ASCII
		return &encoding.ASCIICoder{}
	// case 0b00000011: // LATIN1
	// 	return &encoding.LATIN1Coder{}
	case 0b00001000: // UCS2
		return &encoding.UCS2Coder{}
	default:
		return &encoding.ASCIICoder{}
	}
}
