package pdu

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

	"github.com/warthog618/sms/encoding/gsm7"
)

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{}
)

func (p *SUBMIT_SM) Encode(buf *bytes.Buffer) error {
	if buf == nil {
		return fmt.Errorf("cannot encode into nil buffer")
	}
	// This won't do...
	// TODO: Implement your own encoders and shit
	// ASCII is easy
	// UCS2 should also be fairly easy, use uint16 or something
	// GSM7 will not be easy
	// 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
	asciiEncoder := ascii85.NewEncoder(buf)
	// TODO: Implement encodings bsed on p.data_coding
	messageEncoder := gsm7.NewEncoder()

	p.header.Encode(buf)
	n, err := asciiEncoder.Write([]byte("OOO"))
	if err != nil {
		return err
	}
	log.Println(n)
	// asciiEncoder.Write([]byte(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)
	asciiEncoder.Write([]byte(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)
	asciiEncoder.Write([]byte(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)
	asciiEncoder.Write([]byte(p.schedule_delivery_time))
	buf.Write(NULL_ARR)
	asciiEncoder.Write([]byte(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)
	encodedMsg, err := messageEncoder.Encode([]byte(p.short_message))
	if err != nil {
		return err
	}
	buf.Write(encodedMsg)
	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
	// TODO: Handle encoding based on p.data_coding
	switch p.data_coding {
	case 0b00000000: // GSM7
		size += (len(p.short_message)*7 + 8 - 1) / 8
	case 0b00000001: // ASCII
		size += len(p.short_message)
	case 0b00000011: // LATIN1
		size += len(p.short_message)
	case 0b00001000: // UCS2
		size += len(p.short_message) * 2
	}
	return size
}
func (p *SUBMIT_SM) UpdateSize() {
	p.header.command_length = uint32(p.Size())
	p.sm_length = byte(len(p.short_message))
}
