package device

import (
	"context"
	"errors"
	"testing"
)

func TestSetNetworkATBackendActivatesAndDeactivatesPDP(t *testing.T) {
	client := &transcriptClient{steps: []clientStep{
		{command: `AT+CGDCONT=1,"IPV4V6","internet"`, response: okResponse()},
		{command: "AT+CGATT=1", response: okResponse()},
		{command: "AT+CGACT=1,1", response: okResponse()},
		{command: "AT+CGACT=0,1", response: okResponse()},
	}}
	manager, id := newStartedTestManager(t, client)
	result, err := manager.SetNetwork(context.Background(), id, NetworkRequest{
		Enabled: true, APN: "internet", IPVersion: "IPV4V6",
	})
	if err != nil {
		t.Fatalf("enable network: %v", err)
	}
	if !result.Enabled || result.Backend != "at" || result.APN != "internet" {
		t.Fatalf("enable result = %#v", result)
	}
	result, err = manager.SetNetwork(context.Background(), id, NetworkRequest{
		Enabled: false, APN: "internet", IPVersion: "IP",
	})
	if err != nil {
		t.Fatalf("disable network: %v", err)
	}
	if result.Enabled {
		t.Fatalf("disable result = %#v", result)
	}
	client.assertDone(t)
}

func TestSetNetworkRejectsUnsafeAPNBeforeOpeningModem(t *testing.T) {
	client := &transcriptClient{}
	manager, id := newStartedTestManager(t, client)
	_, err := manager.SetNetwork(context.Background(), id, NetworkRequest{
		Enabled: true, APN: `internet";AT+CFUN=0`, IPVersion: "IP",
	})
	if !errors.Is(err, ErrInvalidNetworkAPN) {
		t.Fatalf("error = %v, want ErrInvalidNetworkAPN", err)
	}
	client.assertDone(t)
}

func TestUSBNetModeReadAndGuardedWrite(t *testing.T) {
	client := &transcriptClient{steps: []clientStep{
		{command: `AT+QCFG="usbnet"`, response: okResponse(`+QCFG: "usbnet",0`)},
		{command: `AT+QCFG="usbnet",1`, response: okResponse()},
	}}
	manager, id := newStartedTestManager(t, client)
	mode, err := manager.USBNetMode(context.Background(), id)
	if err != nil {
		t.Fatalf("read USB mode: %v", err)
	}
	if mode.Mode != 0 || mode.Name != "QMI" {
		t.Fatalf("USB mode = %#v", mode)
	}
	mode, err = manager.SetUSBNetMode(context.Background(), id, 1)
	if err != nil {
		t.Fatalf("write USB mode: %v", err)
	}
	if mode.Mode != 1 || mode.Name != "ECM" {
		t.Fatalf("new USB mode = %#v", mode)
	}
	client.assertDone(t)
}

func TestOperatorSelectionManualAndAutomatic(t *testing.T) {
	client := &transcriptClient{steps: []clientStep{
		{command: `AT+COPS=1,2,"46000",7`, response: okResponse()},
		{command: "AT+COPS?", response: okResponse(`+COPS: 1,2,"46000",7`)},
		{command: "AT+COPS=0", response: okResponse()},
	}}
	manager, id := newStartedTestManager(t, client)
	act := 7
	selection, err := manager.SetOperatorSelection(context.Background(), id, false, "46000", &act)
	if err != nil {
		t.Fatalf("manual selection: %v", err)
	}
	if selection.Mode != 1 || selection.Format != 2 || selection.Operator != "46000" || selection.AccessTechnology != "LTE" {
		t.Fatalf("manual selection = %#v", selection)
	}
	selection, err = manager.SetOperatorSelection(context.Background(), id, true, "", nil)
	if err != nil {
		t.Fatalf("automatic selection: %v", err)
	}
	if selection.Mode != 0 || selection.Operator != "" {
		t.Fatalf("automatic selection = %#v", selection)
	}
	client.assertDone(t)
}

func TestOperatorSelectionRejectsAutomaticFallbackAsSuccess(t *testing.T) {
	client := &transcriptClient{steps: []clientStep{
		{command: `AT+COPS=1,2,"46000",7`, response: okResponse()},
		{command: "AT+COPS?", response: okResponse("+COPS: 0")},
	}}
	manager, id := newStartedTestManager(t, client)
	act := 7
	if _, err := manager.SetOperatorSelection(context.Background(), id, false, "46000", &act); err == nil {
		t.Fatal("manual selection must fail when readback returned automatic mode")
	}
	client.assertDone(t)
}
