package nfc

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/ebfe/scard"
)

var ctx *scard.Context
var readers []string

func die(err error) {
	fmt.Println(err)
	os.Exit(1)
}

func initReader() error {
	var err error
	// Establish a context
	ctx, err = scard.EstablishContext()
	if err != nil {
		return err
	}

	// List available readers
	readers, err = ctx.ListReaders()
	if err != nil {
		return errors.New("讀卡機未連接")
	}

	fmt.Printf("Found %d readers:\n", len(readers))
	for i, reader := range readers {
		fmt.Printf("[%d] %s\n", i, reader)
	}
	return nil
}

func GetNfcId() (string, error) {
	err := initReader()
	if err != nil {
		return "", err
	}

	if len(readers) > 0 {
		//Connect to card
		fmt.Println("Connecting to card in ", readers[0])

		card, err := ctx.Connect(readers[0], scard.ShareExclusive, scard.ProtocolAny)
		if err != nil {
			return "", errors.New("請將卡片放置讀卡機上")
		}
		defer card.Disconnect(scard.ResetCard)

		fmt.Println("Card status:")
		status, err := card.Status()
		if err != nil {
			return "", err
		}

		fmt.Printf("\treader: %s\n\tstate: %x\n\tactive protocol: %x\n\tatr: % x\n",
			status.Reader, status.State, status.ActiveProtocol, status.Atr)

		apdu := []byte{0xFF, 0xCA, 0x00, 0x00, 0x00}
		rsp, err := card.Transmit(apdu)
		if err != nil {
			return "", err
		}

		// Parse UID from response
		if len(rsp) >= 3 && rsp[len(rsp)-2] == 0x90 && rsp[len(rsp)-1] == 0x00 {
			uid := rsp[:len(rsp)-2]
			//將uid reverse
			reverseBytes(uid)
			return strings.ToUpper(fmt.Sprintf("%x", uid)), nil
		}

		return "NFC ID", nil
	}

	return "", fmt.Errorf("No NFC reader found")
}

func WriteNfcCard(data string) (string, error) {
	err := initReader()
	if err != nil {
		return "", err
	}

	if len(readers) > 0 {
		// Connect to card
		fmt.Println("Connecting to card in ", readers[0])
		card, err := ctx.Connect(readers[0], scard.ShareExclusive, scard.ProtocolAny)

		if err != nil {
			return "", err
		}
		defer card.Disconnect(scard.ResetCard)

		fmt.Println("Card status:")
		status, err := card.Status()
		if err != nil {
			return "", err
		}

		fmt.Printf("\treader: %s\n\tstate: %x\n\tactive protocol: %x\n\tatr: % x\n",
			status.Reader, status.State, status.ActiveProtocol, status.Atr)

		url := []byte(data)

		ndef := []byte{
			0x03, byte(len(url) + 5), 0xd1, 0x01,
			byte(len(url) + 1), 0x55, 0x04,
		}

		//將url加入ndef,最後以0xef結尾
		ndef = append(ndef, url...)
		ndef = append(ndef, 0xfe)
		// for _, b := range ndef {
		// 	fmt.Printf("%02x ", b)
		// }
		// fmt.Println()

		//將ndef 4bytes一組
		groupSize := 4
		ndefSize := len(ndef)
		groupCount := ndefSize / groupSize
		if ndefSize%groupSize != 0 {
			groupCount++
		}

		//將ndef分組
		groups := make([][4]byte, groupCount)
		for i := 0; i < groupCount; i++ {
			start := i * groupSize
			end := start + groupSize
			if end > ndefSize {
				end = ndefSize
			}
			copy(groups[i][:], ndef[start:end])
		}

		//將ndef分組後的資料寫入卡片
		for i, group := range groups {

			var cmd = []byte{
				0xFF, 0xD6,
				0x00,
				byte(4 + i),
				0x04,
			}

			cmd = append(cmd, group[:]...)

			fmt.Println(cmd)
			fmt.Println("Transmit:")
			fmt.Printf("\tc-apdu: % x\n", cmd)
			rsp, err := card.Transmit(cmd)
			if err != nil {
				return "", err
			}
			fmt.Printf("\tr-apdu: % x\n", rsp)
		}

		apdu := []byte{0xFF, 0x00, 0x52, 0xFF, 0xFF}
		rsp, err := card.Transmit(apdu)
		if err != nil {
			return "", err
		}
		fmt.Println()
		fmt.Printf("\tr-apdu: % x\n", rsp)
		fmt.Println("Done")
	}

	return "", nil
}

func waitUntilCardPresent() (int, error) {
	rs := make([]scard.ReaderState, len(readers))
	for i := range rs {
		rs[i].Reader = readers[i]
		rs[i].CurrentState = scard.StateUnaware
	}

	for {
		for i := range rs {
			if rs[i].EventState&scard.StatePresent != 0 {
				return i, nil
			}
			rs[i].CurrentState = rs[i].EventState
		}
		err := ctx.GetStatusChange(rs, -1)
		if err != nil {
			return -1, err
		}
	}
}

func reverseBytes(slice []byte) {
	for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
		slice[i], slice[j] = slice[j], slice[i]
	}
}
