"""Test repairs for synology dsm."""

from unittest.mock import AsyncMock, MagicMock, Mock, patch

import pytest
from synology_dsm.api.file_station.models import SynoFileSharedFolder

from homeassistant.components.repairs import DOMAIN as REPAIRS_DOMAIN
from homeassistant.components.synology_dsm.const import (
    CONF_BACKUP_PATH,
    CONF_BACKUP_SHARE,
    DOMAIN,
)
from homeassistant.const import (
    CONF_HOST,
    CONF_MAC,
    CONF_PASSWORD,
    CONF_PORT,
    CONF_SSL,
    CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
from homeassistant.setup import async_setup_component

from .common import mock_dsm_information
from .consts import HOST, MACS, PASSWORD, PORT, USE_SSL, USERNAME

from tests.common import ANY, MockConfigEntry
from tests.components.repairs import process_repair_fix_flow, start_repair_fix_flow
from tests.typing import ClientSessionGenerator, WebSocketGenerator


@pytest.fixture
def mock_dsm_with_filestation():
    """Mock a successful service with filestation support."""
    with patch("homeassistant.components.synology_dsm.common.SynologyDSM") as dsm:
        dsm.login = AsyncMock(return_value=True)
        dsm.update = AsyncMock(return_value=True)

        dsm.surveillance_station.update = AsyncMock(return_value=True)
        dsm.upgrade.update = AsyncMock(return_value=True)
        dsm.utilisation = Mock(cpu_user_load=1, update=AsyncMock(return_value=True))
        dsm.network = Mock(update=AsyncMock(return_value=True), macs=MACS)
        dsm.storage = Mock(
            disks_ids=["sda", "sdb", "sdc"],
            volumes_ids=["volume_1"],
            update=AsyncMock(return_value=True),
        )
        dsm.information = mock_dsm_information()
        dsm.file = AsyncMock(
            get_shared_folders=AsyncMock(
                return_value=[
                    SynoFileSharedFolder(
                        additional=None,
                        is_dir=True,
                        name="HA Backup",
                        path="/ha_backup",
                    )
                ]
            ),
        )
        dsm.logout = AsyncMock(return_value=True)
        yield dsm


@pytest.fixture
async def setup_dsm_with_filestation(
    hass: HomeAssistant,
    mock_dsm_with_filestation: MagicMock,
):
    """Mock setup of synology dsm config entry."""
    with (
        patch(
            "homeassistant.components.synology_dsm.common.SynologyDSM",
            return_value=mock_dsm_with_filestation,
        ),
        patch("homeassistant.components.synology_dsm.PLATFORMS", return_value=[]),
    ):
        entry = MockConfigEntry(
            domain=DOMAIN,
            data={
                CONF_HOST: HOST,
                CONF_PORT: PORT,
                CONF_SSL: USE_SSL,
                CONF_USERNAME: USERNAME,
                CONF_PASSWORD: PASSWORD,
                CONF_MAC: MACS[0],
            },
            options={
                CONF_BACKUP_PATH: None,
                CONF_BACKUP_SHARE: None,
            },
            unique_id="my_serial",
        )
        entry.add_to_hass(hass)
        assert await hass.config_entries.async_setup(entry.entry_id)
        assert await async_setup_component(hass, REPAIRS_DOMAIN, {})
        await hass.async_block_till_done()

        yield mock_dsm_with_filestation


async def test_create_issue(
    hass: HomeAssistant,
    setup_dsm_with_filestation: MagicMock,
    hass_ws_client: WebSocketGenerator,
) -> None:
    """Test the issue is created."""
    ws_client = await hass_ws_client(hass)
    await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()

    assert msg["success"]
    assert len(msg["result"]["issues"]) == 1
    issue = msg["result"]["issues"][0]
    assert issue["breaks_in_ha_version"] is None
    assert issue["domain"] == DOMAIN
    assert issue["issue_id"] == "missing_backup_setup_my_serial"
    assert issue["translation_key"] == "missing_backup_setup"


async def test_missing_backup_ignore(
    hass: HomeAssistant,
    setup_dsm_with_filestation: MagicMock,
    hass_client: ClientSessionGenerator,
    hass_ws_client: WebSocketGenerator,
) -> None:
    """Test missing backup location setup issue is ignored by the user."""
    ws_client = await hass_ws_client(hass)
    client = await hass_client()

    # get repair issues
    await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()
    assert msg["success"]
    assert len(msg["result"]["issues"]) == 1
    issue = msg["result"]["issues"][0]
    assert not issue["ignored"]

    # start repair flow
    data = await start_repair_fix_flow(client, DOMAIN, "missing_backup_setup_my_serial")

    flow_id = data["flow_id"]
    assert data["description_placeholders"] == {
        "docs_url": "https://www.home-assistant.io/integrations/synology_dsm/#backup-location"
    }
    assert data["step_id"] == "init"
    assert data["menu_options"] == ["confirm", "ignore"]

    # seelct to ignore the flow
    data = await process_repair_fix_flow(
        client, flow_id, json={"next_step_id": "ignore"}
    )
    assert data["type"] == "abort"
    assert data["reason"] == "ignored"

    # check issue is ignored
    await ws_client.send_json({"id": 2, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()
    assert msg["success"]
    assert len(msg["result"]["issues"]) == 1
    issue = msg["result"]["issues"][0]
    assert issue["ignored"]


async def test_missing_backup_success(
    hass: HomeAssistant,
    setup_dsm_with_filestation: MagicMock,
    hass_client: ClientSessionGenerator,
    hass_ws_client: WebSocketGenerator,
) -> None:
    """Test missing backup location repair flow is fully processed."""
    ws_client = await hass_ws_client(hass)
    client = await hass_client()
    entries = hass.config_entries.async_entries(DOMAIN)
    assert len(entries) == 1
    entry = entries[0]
    assert entry.options == {"backup_path": None, "backup_share": None}

    # get repair issues
    await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()
    assert msg["success"]
    assert len(msg["result"]["issues"]) == 1
    issue = msg["result"]["issues"][0]
    assert not issue["ignored"]

    # start repair flow
    data = await start_repair_fix_flow(client, DOMAIN, "missing_backup_setup_my_serial")

    flow_id = data["flow_id"]
    assert data["description_placeholders"] == {
        "docs_url": "https://www.home-assistant.io/integrations/synology_dsm/#backup-location"
    }
    assert data["step_id"] == "init"
    assert data["menu_options"] == ["confirm", "ignore"]

    # seelct to confirm the flow
    data = await process_repair_fix_flow(
        client, flow_id, json={"next_step_id": "confirm"}
    )
    assert data["step_id"] == "confirm"
    assert data["type"] == "form"

    # fill out the form and submit
    data = await process_repair_fix_flow(
        client,
        flow_id,
        json={"backup_share": "/ha_backup", "backup_path": "backup_ha_dev"},
    )
    assert data["type"] == "create_entry"
    assert entry.options == {
        "backup_path": "backup_ha_dev",
        "backup_share": "/ha_backup",
    }


async def test_missing_backup_no_shares(
    hass: HomeAssistant,
    setup_dsm_with_filestation: MagicMock,
    hass_client: ClientSessionGenerator,
    hass_ws_client: WebSocketGenerator,
) -> None:
    """Test the missing backup location setup repair flow errors out."""
    ws_client = await hass_ws_client(hass)
    client = await hass_client()

    # get repair issues
    await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()
    assert msg["success"]
    assert len(msg["result"]["issues"]) == 1

    # start repair flow
    data = await start_repair_fix_flow(client, DOMAIN, "missing_backup_setup_my_serial")

    flow_id = data["flow_id"]
    assert data["description_placeholders"] == {
        "docs_url": "https://www.home-assistant.io/integrations/synology_dsm/#backup-location"
    }
    assert data["step_id"] == "init"
    assert data["menu_options"] == ["confirm", "ignore"]

    # inject error
    setup_dsm_with_filestation.file.get_shared_folders.return_value = []

    # select to confirm the flow
    data = await process_repair_fix_flow(
        client, flow_id, json={"next_step_id": "confirm"}
    )
    assert data["type"] == "abort"
    assert data["reason"] == "no_shares"


@pytest.mark.parametrize(
    "ignore_missing_translations",
    ["component.synology_dsm.issues.other_issue.title"],
)
async def test_other_fixable_issues(
    hass: HomeAssistant,
    setup_dsm_with_filestation: MagicMock,
    hass_client: ClientSessionGenerator,
    hass_ws_client: WebSocketGenerator,
) -> None:
    """Test fixing another issue."""
    ws_client = await hass_ws_client(hass)
    client = await hass_client()

    await ws_client.send_json({"id": 1, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()

    assert msg["success"]

    issue = {
        "breaks_in_ha_version": None,
        "domain": DOMAIN,
        "issue_id": "other_issue",
        "is_fixable": True,
        "severity": "error",
        "translation_key": "other_issue",
    }
    ir.async_create_issue(
        hass,
        issue["domain"],
        issue["issue_id"],
        is_fixable=issue["is_fixable"],
        severity=issue["severity"],
        translation_key=issue["translation_key"],
    )

    await ws_client.send_json({"id": 2, "type": "repairs/list_issues"})
    msg = await ws_client.receive_json()

    assert msg["success"]
    results = msg["result"]["issues"]
    assert {
        "breaks_in_ha_version": None,
        "created": ANY,
        "dismissed_version": None,
        "domain": "synology_dsm",
        "ignored": False,
        "is_fixable": True,
        "issue_domain": None,
        "issue_id": "other_issue",
        "learn_more_url": None,
        "severity": "error",
        "translation_key": "other_issue",
        "translation_placeholders": None,
    } in results

    data = await start_repair_fix_flow(client, DOMAIN, "other_issue")

    flow_id = data["flow_id"]
    assert data["step_id"] == "confirm"

    data = await process_repair_fix_flow(client, flow_id)

    assert data["type"] == "create_entry"
    await hass.async_block_till_done()
