package hwapi

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

	"github.com/9elements/converged-security-suite/v2/pkg/registers"
	"github.com/9elements/go-linux-lowlevel-hw/pkg/hwapi"
	"github.com/digitalocean/go-smbios/smbios"
)

type pcmock struct {
	ReadMemoryFunc func(uint64) byte
}

func (n pcmock) CPUBlacklistTXTSupport() bool {
	return false
}

func (n pcmock) CPUWhitelistTXTSupport() bool {
	return false
}

func (n pcmock) VersionString() string {
	return ""
}

func (n pcmock) HasSMX() bool {
	return false
}

func (n pcmock) HasVMX() bool {
	return false
}

func (n pcmock) HasMTRR() bool {
	return false
}

func (n pcmock) ProcessorBrandName() string {
	return ""
}
func (n pcmock) CPUSignature() uint32 {
	return 0
}
func (n pcmock) CPUSignatureFull() (uint32, uint32, uint32, uint32) {
	return 0, 0, 0, 0
}
func (n pcmock) CPULogCount() uint32 {
	return 0
}

func (n pcmock) IsReservedInE820(start uint64, end uint64) (bool, error) {
	return false, fmt.Errorf("not implemented")
}
func (n pcmock) UsableMemoryAbove4G() (size uint64, err error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) UsableMemoryBelow4G() (size uint64, err error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) LookupIOAddress(addr uint64, regs hwapi.VTdRegisters) ([]uint64, error) {
	return []uint64{}, fmt.Errorf("not implemented")
}

func (n pcmock) AddressRangesIsDMAProtected(first, end uint64) (bool, error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) ReadMSR(msr int64) []uint64 {
	panic("not implemented")
}

func (n pcmock) ReadMSRAllCores(msr int64) (uint64, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) HasSMRR() (bool, error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) GetSMRRInfo() (hwapi.SMRR, error) {
	return hwapi.SMRR{}, fmt.Errorf("not implemented")
}

func (n pcmock) IA32FeatureControlIsLocked() (bool, error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) IA32PlatformID() (uint64, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) AllowsVMXInSMX() (bool, error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) TXTLeavesAreEnabled() (bool, error) {
	return false, fmt.Errorf("not implemented")
}
func (n pcmock) IA32DebugInterfaceEnabledOrLocked() (*hwapi.IA32Debug, error) {
	return nil, fmt.Errorf("not implemented")
}

func (n pcmock) GetMSRRegisters() (registers.Registers, error) {
	return nil, fmt.Errorf("not implemented")
}

func (n pcmock) PCIEnumerateVisibleDevices(cb func(d hwapi.PCIDevice) (abort bool)) (err error) {
	return fmt.Errorf("not implemented")
}

func (n pcmock) PCIReadConfig8(d hwapi.PCIDevice, off int) (uint8, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) PCIReadConfig16(d hwapi.PCIDevice, off int) (uint16, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) PCIReadConfig32(d hwapi.PCIDevice, off int) (uint32, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) PCIWriteConfig8(d hwapi.PCIDevice, off int, val uint8) error {
	return fmt.Errorf("not implemented")
}

func (n pcmock) PCIWriteConfig16(d hwapi.PCIDevice, off int, val uint16) error {
	return fmt.Errorf("not implemented")
}

func (n pcmock) PCIWriteConfig32(d hwapi.PCIDevice, off int, val uint32) error {
	return fmt.Errorf("not implemented")
}

func (n pcmock) PCIReadVendorID(d hwapi.PCIDevice) (uint16, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) PCIReadDeviceID(d hwapi.PCIDevice) (uint16, error) {
	return 0, fmt.Errorf("not implemented")
}

func (n pcmock) ReadHostBridgeTseg() (uint32, uint32, error) {
	return 0, 0, fmt.Errorf("not implemented")
}

func (n pcmock) ReadHostBridgeDPR() (hwapi.DMAProtectedRange, error) {
	return hwapi.DMAProtectedRange{}, fmt.Errorf("not implemented")
}

//MockPCReadMemory emulates a x86_64 platform memory map
func MockPCReadMemory(addr uint64) byte {
	mem := map[uint64][]byte{
		0xFED30000: []byte{
			0x01, 0xa7, 0x86, 0x80, 0x6b, 0xc8, 0x7b, 0x02, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x6e, 0x62, 0x44, 0x4f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
			0x00, 0x08, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x00,
			0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00, 0x00, 0x00, 0x00,
		},
	}
	for k, v := range mem {
		if addr >= k && addr < k+uint64(len(v)) {
			addr -= k
			return v[addr]
		}
	}

	return 0xff

}

func (n pcmock) ReadPhys(addr int64, data hwapi.UintN) error {
	buf := make([]byte, int(data.Size()))
	for i := int64(0); i < data.Size(); i++ {
		buf[i] = n.ReadMemoryFunc(uint64(addr + i))
	}
	r := bytes.NewReader(buf)

	err := binary.Read(r, binary.LittleEndian, data)
	if err != nil {
		return err
	}
	return nil
}

func (n pcmock) ReadPhysBuf(addr int64, buf []byte) error {
	buffer := make([]byte, len(buf))
	for i := 0; i < len(buf); i++ {
		buffer[i] = n.ReadMemoryFunc(uint64(addr + int64(i)))
	}
	r := bytes.NewReader(buffer)

	err := binary.Read(r, binary.LittleEndian, buf)
	if err != nil {
		return err
	}
	return nil
}

func (n pcmock) WritePhys(addr int64, data hwapi.UintN) error {
	return nil
}

func (n pcmock) NewTPM() (*hwapi.TPM, error) {
	return nil, fmt.Errorf("not implemented")
}

func (n pcmock) NVLocked(tpmCon *hwapi.TPM) (bool, error) {
	return false, nil
}

func (n pcmock) ReadNVPublic(tpmCon *hwapi.TPM, index uint32) ([]byte, error) {
	return []byte{}, fmt.Errorf("not implemented")
}
func (n pcmock) NVReadValue(tpmCon *hwapi.TPM, index uint32, password string, size, offhandle uint32) ([]byte, error) {
	return []byte{}, fmt.Errorf("not implemented")
}
func (n pcmock) ReadPCR(tpmCon *hwapi.TPM, pcr uint32) ([]byte, error) {
	return []byte{}, fmt.Errorf("not implemented")
}

func (n pcmock) GetACPITable(arg string) ([]byte, error) {
	return []byte{}, fmt.Errorf("not implemented")
}

func (n pcmock) GetACPITableSysFS(arg string) ([]byte, error) {
	return []byte{}, fmt.Errorf("not implemented")
}

func (n pcmock) GetACPITableDevMem(s string) ([]byte, error) {
	return []byte{}, fmt.Errorf("not implemented")
}

func (n pcmock) IterateOverSMBIOSTables(m uint8, callback func(s *smbios.Structure) bool) (ret bool, err error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) IterateOverSMBIOSTablesType0(callback func(t0 *hwapi.SMBIOSType0) bool) (ret bool, err error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) IterateOverSMBIOSTablesType17(callback func(t17 *hwapi.SMBIOSType17) bool) (ret bool, err error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) IterateOverE820Ranges(target string, callback func(start uint64, end uint64) bool) (bool, error) {
	return false, fmt.Errorf("not implemented")
}

func (n pcmock) PCIReadConfigSpace(d hwapi.PCIDevice, off int, len int) ([]byte, error) {
	return nil, fmt.Errorf("not implemented")
}

func (n pcmock) PCIWriteConfigSpace(d hwapi.PCIDevice, off int, val interface{}) error {
	return fmt.Errorf("not implemented")
}

//GetPcMock returns APIInterfaces for mocking the hwapi used in unittests
func GetPcMock(ReadMemoryFunc func(uint64) byte) hwapi.LowLevelHardwareInterfaces {
	return pcmock{
		ReadMemoryFunc,
	}
}
