package msc

import (
	"machine"
	"machine/usb"
)

func setupPacketHandler(setup usb.Setup) bool {
	if MSC != nil {
		return MSC.setupPacketHandler(setup)
	}
	return false
}

func (m *msc) setupPacketHandler(setup usb.Setup) bool {
	ok := false
	wValue := (uint16(setup.WValueH) << 8) | uint16(setup.WValueL)
	switch setup.BRequest {
	case usb.CLEAR_FEATURE:
		if setup.BmRequestType == 0x02 { // Host-to-Device | Standard | Endpoint
			ok = m.handleClearFeature(setup, wValue)
		}
	case usb.GET_MAX_LUN:
		if setup.BmRequestType == 0xA1 { // Device-to-Host | Class | Interface
			ok = m.handleGetMaxLun(setup, wValue)
		}
	case usb.MSC_RESET:
		if setup.BmRequestType == 0x21 { // Host-to-Device | Class | Interface
			ok = m.handleReset(setup, wValue)
		}
	}
	return ok
}

// Handles the CLEAR_FEATURE request for clearing ENDPOINT_HALT/stall
func (m *msc) handleClearFeature(setup usb.Setup, wValue uint16) bool {
	ok := false
	// wValue is the feature selector (0x00 for ENDPOINT_HALT)
	// We aren't handling any other feature selectors
	// https://wiki.osdev.org/Universal_Serial_Bus#CLEAR_FEATURE
	if wValue != 0 {
		return ok
	}
	// Clearing the stall is not enough, continue stalling until a reset is received first
	// 6.6.1 CBW Not Valid
	// If the CBW is not valid, the device shall STALL the Bulk-In pipe. Also, the device
	// shall either STALL the Bulk-Out pipe, or the device shall accept and discard any
	// Bulk-Out data. The device shall maintain this state until a Reset Recovery
	// For Reset Recovery the host shall issue in the following order: :
	// (a) a Bulk-Only Mass Storage Reset (handleReset())
	// (b) a Clear Feature HALT to the Bulk-In endpoint (clear stall IN)
	// (c) a Clear Feature HALT to the Bulk-Out endpoint (clear stall OUT)
	// https://usb.org/sites/default/files/usbmassbulk_10.pdf

	if m.state == mscStateNeedReset {
		wIndex := uint8(setup.WIndex & 0x7F)
		if wIndex == usb.MSC_ENDPOINT_IN {
			if (setup.WIndex & 0x80) != 0 {
				m.stallEndpointIn(wIndex)
			} else {
				m.stallEndpointOut(wIndex)
			}
		}
		machine.SendZlp()
		return true
	}

	wIndex := uint8(setup.WIndex & 0x7F)
	if wIndex == usb.MSC_ENDPOINT_IN {
		if (setup.WIndex & 0x80) != 0 {
			m.clearStallEndpointIn(wIndex)
			ok = true
			if m.state == mscStateStatus {
				m.sendCSW(m.respStatus)
			}
		} else {
			m.clearStallEndpointOut(wIndex)
			ok = true
		}
	}

	if ok {
		machine.SendZlp()
	}
	return ok
}

// 3.2 Get Max LUN
// https://usb.org/sites/default/files/usbmassbulk_10.pdf
func (m *msc) handleGetMaxLun(setup usb.Setup, wValue uint16) bool {
	if setup.WIndex != mscInterface || setup.WLength != 1 || wValue != 0 {
		return false
	}
	// Send the maximum LUN ID number (zero-indexed, so n-1) supported by the device
	m.resetBuffer(1) // Shrink buffer to 1 byte
	m.buf[0] = m.maxLUN
	return machine.SendUSBInPacket(usb.CONTROL_ENDPOINT, m.buf)
}

// 3.1 Bulk-Only Mass Storage Reset
// https://usb.org/sites/default/files/usbmassbulk_10.pdf
func (m *msc) handleReset(setup usb.Setup, wValue uint16) bool {
	if setup.WIndex != mscInterface || setup.WLength != 0 || wValue != 0 {
		return false
	}
	// Reset to command waiting state
	m.state = mscStateCmd

	// Reset transfer state
	m.resetBuffer(0)
	m.senseKey = 0
	m.addlSenseCode = 0
	m.addlSenseQualifier = 0

	// Send a zero-length packet (ZLP) to indicate the reset is complete
	machine.SendZlp()

	// Return true to indicate successful reset
	return true
}

func (m *msc) stallEndpointIn(ep uint8) {
	if ep == usb.CONTROL_ENDPOINT {
		machine.USBDev.SetStallEPIn(usb.CONTROL_ENDPOINT)
		return
	}
	m.txStalled = true
	machine.USBDev.SetStallEPIn(uint32(ep))
}

func (m *msc) stallEndpointOut(ep uint8) {
	m.rxStalled = true
	machine.USBDev.SetStallEPOut(uint32(ep))
}

func (m *msc) clearStallEndpointIn(ep uint8) {
	machine.USBDev.ClearStallEPIn(uint32(ep))
	m.txStalled = false
}

func (m *msc) clearStallEndpointOut(ep uint8) {
	machine.USBDev.ClearStallEPOut(uint32(ep))
	m.rxStalled = false
}

func (m *msc) setStringField(field []byte, value string) {
	copy(field, []byte(value))
	for i := len(value); i < len(field); i++ {
		field[i] = 0x20 // Fill remaining bytes with spaces
	}
}

func (m *msc) SetVendorID(vendorID string) {
	m.setStringField(m.vendorID[:], vendorID)
}

func (m *msc) SetProductID(productID string) {
	m.setStringField(m.productID[:], productID)
}

func (m *msc) SetProductRev(productRev string) {
	m.setStringField(m.productRev[:], productRev)
}

func SetVendorID(vendorID string) {
	if MSC != nil {
		MSC.SetVendorID(vendorID)
	}
}
func SetProductID(productID string) {
	if MSC != nil {
		MSC.SetProductID(productID)
	}
}
func SetProductRev(productRev string) {
	if MSC != nil {
		MSC.SetProductRev(productRev)
	}
}
