/* usbfs fd 登记表:把调用方打开的 /dev/bus/usb/B/A 映射到桥接句柄 */
#include "compat.h"

typedef struct {
    int fd;         /* 调用方打开的 usbfs fd */
    int bus;
    int addr;
    int handle;     /* 桥接句柄,首次 ioctl 时惰性打开;-1 表示尚未打开 */
} dev_fd_map;

static dev_fd_map g_devs[OHB_MAX_DEV_FDS];
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
/* 没有登记项时跳过加锁扫描:close/ioctl 是全进程热路径 */
static volatile int g_count = 0;

int ohb_parse_dev_path(const char *path, int *bus, int *addr) {
    if (!path || strncmp(path, OHB_DEV_PREFIX, sizeof(OHB_DEV_PREFIX) - 1) != 0) {
        return 0;
    }
    return sscanf(path, "/dev/bus/usb/%d/%d", bus, addr) == 2;
}

void ohb_dev_register(int fd, int bus, int addr) {
    pthread_mutex_lock(&g_lock);
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd == fd) {
            g_devs[i].bus = bus;
            g_devs[i].addr = addr;
            g_devs[i].handle = -1;
            pthread_mutex_unlock(&g_lock);
            return;
        }
    }
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd == 0) {
            g_devs[i].fd = fd;
            g_devs[i].bus = bus;
            g_devs[i].addr = addr;
            g_devs[i].handle = -1;
            g_count++;
            break;
        }
    }
    pthread_mutex_unlock(&g_lock);
}

int ohb_dev_lookup(int fd) {
    if (g_count == 0) {
        return -2;
    }
    int bus = 0, addr = 0, handle = -1;
    pthread_mutex_lock(&g_lock);
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd == fd) {
            bus = g_devs[i].bus;
            addr = g_devs[i].addr;
            handle = g_devs[i].handle;
            break;
        }
    }
    pthread_mutex_unlock(&g_lock);
    if (bus == 0) {
        return -2;
    }
    if (handle >= 0) {
        return handle;
    }
    /* 惰性打开:桥接侧 connectDevice 一次,之后一直复用。
     * 地址可能已失效(设备重新枚举过),ohb_bridge_open_ex 会用历史 VID/PID 重定位。 */
    int h = -1, nb = bus, na = addr, vid = 0, pid = 0;
    if (ohb_bridge_open_ex(bus, addr, &h, &nb, &na, &vid, &pid) != 0) {
        return -1;
    }
    ohb_ident_remember(nb, na, vid, pid);
    pthread_mutex_lock(&g_lock);
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd == fd) {
            g_devs[i].handle = h;
            g_devs[i].bus = nb;
            g_devs[i].addr = na;
            break;
        }
    }
    pthread_mutex_unlock(&g_lock);
    /* read() 要按新地址去伪造树里取描述符链 */
    ohb_acq_set_addr(fd, nb, na);
    return h;
}

/* 按桥接句柄反查设备位置:字符串描述符要在本地作答,需要知道去伪造树里读哪一台 */
int ohb_dev_addr_by_handle(int handle, int *bus, int *addr) {
    int ok = 0;
    if (handle < 0) {
        return 0;
    }
    pthread_mutex_lock(&g_lock);
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd != 0 && g_devs[i].handle == handle) {
            *bus = g_devs[i].bus;
            *addr = g_devs[i].addr;
            ok = 1;
            break;
        }
    }
    pthread_mutex_unlock(&g_lock);
    return ok;
}

void ohb_dev_unregister(int fd) {
    if (g_count == 0) {
        return;
    }
    int handle = -1;
    pthread_mutex_lock(&g_lock);
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd == fd) {
            handle = g_devs[i].handle;
            g_devs[i].fd = 0;
            g_devs[i].bus = 0;
            g_devs[i].addr = 0;
            g_devs[i].handle = -1;
            if (g_count > 0) {
                g_count--;
            }
            break;
        }
    }
    pthread_mutex_unlock(&g_lock);
    if (handle >= 0) {
        char cmd[64], reply[128];
        snprintf(cmd, sizeof(cmd), "close %d", handle);
        ohb_bridge_cmd(cmd, reply, sizeof(reply));
    }
}

int ohb_dev_resolve_proc(int fd, int *bus, int *addr) {    ohb_real_init();
    char linkp[64];
    char target[512];
    snprintf(linkp, sizeof(linkp), "/proc/self/fd/%d", fd);
    ssize_t n = g_real_readlink(linkp, target, sizeof(target) - 1);
    if (n <= 0) {
        return 0;
    }
    target[n] = '\0';
    if (!ohb_parse_dev_path(target, bus, addr)) {
        return 0;
    }
    ohb_dev_register(fd, *bus, *addr);
    return 1;
}

/* ── usbfs 的 read() 语义 ──
 *
 * 经典 usbfs 里,对设备节点 read() 会返回完整描述符链(device + config + interface +
 * endpoint)。adb 的 usb_linux 正是这么读的:
 *     int fd = open("/dev/bus/usb/001/003", O_RDONLY);
 *     desclength = read(fd, devdesc, 4096);
 * 鸿蒙的 usbfs 不实现这个 read(返回 0),adb 因此判定"descriptor too small"跳过设备。
 * 这里用 ArkTS 侧生成的 descriptors 文件来满足它 —— 数据本来就是我们伪造的。
 */
#define OHB_MAX_ACQ 32

typedef struct {
    int fd;
    int bus;
    int addr;
    int off;        /* 已喂出的字节数(描述符链只读一次,之后返回 0=EOF) */
} acq_entry;

static acq_entry g_acq[OHB_MAX_ACQ];
static pthread_mutex_t g_acq_lock = PTHREAD_MUTEX_INITIALIZER;

void ohb_acq_register(int fd, int bus, int addr) {
    pthread_mutex_lock(&g_acq_lock);
    for (int i = 0; i < OHB_MAX_ACQ; i++) {
        if (g_acq[i].fd == fd || g_acq[i].fd == 0) {
            g_acq[i].fd = fd;
            g_acq[i].bus = bus;
            g_acq[i].addr = addr;
            g_acq[i].off = 0;
            break;
        }
    }
    pthread_mutex_unlock(&g_acq_lock);
    /* 同时登记到 ioctl 表:未翻译的请求(如 SUBMITURB)会落到真实内核 ioctl */
    ohb_dev_register(fd, bus, addr);
}

int ohb_acq_lookup(int fd, int *bus, int *addr) {
    int found = 0;
    pthread_mutex_lock(&g_acq_lock);
    for (int i = 0; i < OHB_MAX_ACQ; i++) {
        if (g_acq[i].fd == fd && fd != 0) {
            *bus = g_acq[i].bus;
            *addr = g_acq[i].addr;
            found = 1;
            break;
        }
    }
    pthread_mutex_unlock(&g_acq_lock);
    return found;
}

int ohb_acq_lookup_rdev(unsigned int major_no, unsigned int minor_no, int *bus, int *addr) {
    if (major_no != 189) {      /* USB_DEVICE_MAJOR */
        return 0;
    }
    *bus = (int)((minor_no >> 8) & 0xff);
    *addr = (int)(minor_no & 0xff);
    return *bus > 0 && *addr > 0;
}

/** fd 是否仍被本层接管(acq 表或 dev 表任一命中)。无副作用,供阻塞等待判断唤醒用。 */
int ohb_dev_known(int fd) {
    if (fd <= 0) {
        return 0;
    }
    int b = 0, a = 0;
    if (ohb_acq_lookup(fd, &b, &a)) {
        return 1;
    }
    if (g_count == 0) {
        return 0;
    }
    int found = 0;
    pthread_mutex_lock(&g_lock);
    for (int i = 0; i < OHB_MAX_DEV_FDS; i++) {
        if (g_devs[i].fd == fd) {
            found = 1;
            break;
        }
    }
    pthread_mutex_unlock(&g_lock);
    return found;
}

void ohb_acq_set_addr(int fd, int bus, int addr) {    pthread_mutex_lock(&g_acq_lock);
    for (int i = 0; i < OHB_MAX_ACQ; i++) {
        if (g_acq[i].fd == fd && fd != 0) {
            g_acq[i].bus = bus;
            g_acq[i].addr = addr;
            break;
        }
    }
    pthread_mutex_unlock(&g_acq_lock);
}

/* ── 设备身份表:(bus, addr) → VID/PID ──
 *
 * 设备重新枚举后 bus/devAddress 会变(实测 1-6 → 1-7 → 1-8),而程序缓存的是旧地址。
 * 只靠地址已经找不到设备,但 VID/PID 不变 —— 记住历史映射,就能把旧地址翻译回"是哪台设备",
 * 再让 ArkTS 侧按身份反查出新地址。对程序完全透明。 */
#define OHB_MAX_IDENT 32

typedef struct {
    int bus, addr, vid, pid;
} ident_entry;

static ident_entry g_ident[OHB_MAX_IDENT];
static int g_ident_count = 0;
static pthread_mutex_t g_ident_lock = PTHREAD_MUTEX_INITIALIZER;

void ohb_ident_remember(int bus, int addr, int vid, int pid) {
    if (bus <= 0 || addr <= 0 || (vid == 0 && pid == 0)) {
        return;
    }
    pthread_mutex_lock(&g_ident_lock);
    int slot = -1;
    for (int i = 0; i < g_ident_count; i++) {
        if (g_ident[i].bus == bus && g_ident[i].addr == addr) {
            slot = i;
            break;
        }
    }
    if (slot < 0 && g_ident_count < OHB_MAX_IDENT) {
        slot = g_ident_count++;
    }
    if (slot >= 0) {
        g_ident[slot].bus = bus;
        g_ident[slot].addr = addr;
        g_ident[slot].vid = vid;
        g_ident[slot].pid = pid;
    }
    pthread_mutex_unlock(&g_ident_lock);
}

int ohb_ident_lookup(int bus, int addr, int *vid, int *pid) {
    int found = 0;
    pthread_mutex_lock(&g_ident_lock);
    for (int i = 0; i < g_ident_count; i++) {
        if (g_ident[i].bus == bus && g_ident[i].addr == addr) {
            *vid = g_ident[i].vid;
            *pid = g_ident[i].pid;
            found = 1;
            break;
        }
    }
    pthread_mutex_unlock(&g_ident_lock);
    return found;
}

/** 地址还有效时就从伪造树学走 VID/PID。
 *  读两个小文件即可,不用访问桥接;设备一旦重新枚举,这两项就是唯一线索。 */
void ohb_ident_learn_from_tree(int bus, int addr) {
    int vid = 0, pid = 0;
    if (ohb_ident_lookup(bus, addr, &vid, &pid)) {
        return;
    }
    ohb_real_init();
    char path[512];
    char buf[64];
    for (int pass = 0; pass < 2; pass++) {
        snprintf(path, sizeof(path), "%s/%d-%d/%s", OHB_FAKE_DEVICES, bus, addr,
                 pass == 0 ? "idVendor" : "idProduct");
        int f = g_real_open(path, O_RDONLY, 0);
        if (f < 0) {
            return;
        }
        ssize_t n = g_real_read(f, buf, sizeof(buf) - 1);
        g_real_close(f);
        if (n <= 0) {
            return;
        }
        buf[n] = '\0';
        int v = (int)strtol(buf, NULL, 16);     /* 伪造树里是 0x22d9 这种形式 */
        if (pass == 0) {
            vid = v;
        } else {
            pid = v;
        }
    }
    ohb_ident_remember(bus, addr, vid, pid);
    ohb_trace("ident %d-%d = %d:%d", bus, addr, vid, pid);
}

int ohb_usbfs_read(int fd, void *buf, size_t len) {
    if (!buf || len == 0) {
        return -1;
    }
    int bus = 0, addr = 0, off = -1;
    pthread_mutex_lock(&g_acq_lock);
    for (int i = 0; i < OHB_MAX_ACQ; i++) {
        if (g_acq[i].fd == fd && fd != 0) {
            bus = g_acq[i].bus;
            addr = g_acq[i].addr;
            off = g_acq[i].off;
            break;
        }
    }
    pthread_mutex_unlock(&g_acq_lock);
    if (off < 0) {
        return -1;      /* 不是我们接管的设备 fd */
    }
    if (off > 0) {
        return 0;       /* 描述符链只给一次,后续是 EOF(与 usbfs 一致) */
    }

    char path[512];
    snprintf(path, sizeof(path), "%s/%d-%d/descriptors", OHB_FAKE_DEVICES, bus, addr);
    ohb_real_init();
    int f = g_real_open(path, O_RDONLY, 0);
    if (f < 0) {
        return 0;
    }
    unsigned char tmp[4096];
    ssize_t n = read(f, tmp, sizeof(tmp));
    g_real_close(f);
    if (n <= 0) {
        return 0;
    }
    size_t copy = (size_t)n > len ? len : (size_t)n;
    memcpy(buf, tmp, copy);
    pthread_mutex_lock(&g_acq_lock);
    for (int i = 0; i < OHB_MAX_ACQ; i++) {
        if (g_acq[i].fd == fd) {
            g_acq[i].off = (int)copy;
            break;
        }
    }
    pthread_mutex_unlock(&g_acq_lock);
    return (int)copy;
}

/* ── fork 安全 ── */
void ohb_devs_fork_prepare(void) {
    pthread_mutex_lock(&g_lock);
}

void ohb_devs_fork_parent(void) {
    pthread_mutex_unlock(&g_lock);
}

void ohb_devs_fork_child(void) {
    pthread_mutex_init(&g_lock, NULL);
    memset(g_devs, 0, sizeof(g_devs));
    g_count = 0;
    pthread_mutex_init(&g_acq_lock, NULL);
    memset(g_acq, 0, sizeof(g_acq));
    pthread_mutex_init(&g_ident_lock, NULL);
    memset(g_ident, 0, sizeof(g_ident));
    g_ident_count = 0;
}