# Copyright (c) 2012-2024, Abilian SAS

from __future__ import annotations

import re
from typing import TYPE_CHECKING

from flask import g, url_for
from pytest import fixture
from toolz import first

from abilian.core.models.subjects import User
from abilian.sbe.apps.communities.models import READER, Community
from abilian.sbe.apps.wiki import views
from abilian.sbe.apps.wiki.models import WikiPage
from abilian.services import get_service
from tests.util import client_login

if TYPE_CHECKING:
    from flask_sqlalchemy import SQLAlchemy

    from abilian.app import Application


@fixture
def user1(db):
    user = User(
        email="user_1@example.com",
        password="azerty",  # noqa: S106
        can_login=True,
    )
    db.session.add(user)
    return user


@fixture
def user2(db):
    user = User(
        email="user_2@example.com",
        password="azerty",  # noqa: S106
        can_login=True,
    )
    db.session.add(user)
    return user


@fixture
def user3(db):
    user = User(
        email="user_3@example.com",
        password="azerty",  # noqa: S106
        can_login=True,
    )
    db.session.add(user)
    return user


@fixture
def community1(db, user1):
    community = Community(name="Community 1")
    community.set_membership(user1, READER)
    db.session.add(community)
    return community


@fixture
def community2(db, user2):
    community = Community(name="Community 2")
    community.set_membership(user2, READER)
    db.session.add(community)
    return community


def test_home(client, community1, user1) -> None:
    with client_login(client, user1):
        response = client.get(url_for("wiki.index", community_id=community1.slug))
        assert response.status_code == 302

        response = client.get(
            url_for("wiki.page", title="Home", community_id=community1.slug)
        )
        assert response.status_code == 200


def test_create_page_initial_form(client, community1, user1) -> None:
    with client_login(client, user1):
        g.community = community1
        view = views.PageCreate()
        view.prepare_args([], {})
        form = view.form
        assert form["last_revision_id"].data is None


def test_wiki_indexed(
    community1,
    community2,
    admin_user,
    user1,
    user2,
    user3,
    app: Application,
    db: SQLAlchemy,
    client,
    monkeypatch,
) -> None:
    monkeypatch.setenv("TESTING_DIRECT_FUNCTION_CALL", "testing")
    SERVICES = ("security", "indexing")
    for svc_name in SERVICES:
        svc = get_service(svc_name)
        if not svc.running:
            svc.start()

    get_service("indexing")

    with client_login(client, admin_user):
        page1 = WikiPage(title="Community 1", community=community1)
        db.session.add(page1)

        page2 = WikiPage(title="Community 2: other", community=community2)
        db.session.add(page2)

        db.session.commit()

    obj_types = (WikiPage.entity_type,)
    with client_login(client, user3):
        res = svc.search("community", object_types=obj_types)
        assert len(res) == 0

    with client_login(client, user1):
        res = svc.search("community", object_types=obj_types)
        assert len(res) == 1

        hit = res[0]
        assert hit["object_key"] == page1.object_key

    with client_login(client, user2):
        res = svc.search("community", object_types=obj_types)
        assert len(res) == 1

        hit = res[0]
        assert hit["object_key"] == page2.object_key


def test_create_page(community1, app, admin_user, client) -> None:
    community = community1

    with client_login(client, admin_user):
        url = url_for("wiki.page_new", community_id=community.slug)
        url += "?title=Some+page+name"
        response = client.get(url)
        assert response.status_code == 200
        # make sure the title is filled when comming from wikilink
        assert 'value="Some page name"' in response.get_data(as_text=True)

        title = "Some page"
        body = "LuuP3jai"
        url = url_for("wiki.page_new", community_id=community.slug)
        data = {"title": title, "body_src": body, "__action": "create"}
        response = client.post(url, data=data)
        assert response.status_code == 302

        url = url_for("wiki.page", community_id=community.slug, title=title)
        response = client.get(url)
        assert response.status_code == 200
        assert body in response.get_data(as_text=True)

        # edit
        url = url_for("wiki.page_edit", community_id=community.slug, title=title)
        response = client.get(url)
        assert response.status_code == 200

        # Slightly hackish way to get the page_id
        line = first(
            l
            for l in response.get_data(as_text=True).split("\n")
            if 'name="page_id"' in l
        )
        m = re.search(r'value="(.*?)"', line)
        page_id = int(m.group(1))

        url = url_for("wiki.page_changes", community_id=community.slug, title=title)
        response = client.get(url)
        assert response.status_code == 200

        url = url_for("wiki.page_source", community_id=community.slug, title=title)
        response = client.get(url)
        assert response.status_code == 200

        url = url_for("wiki.page_edit", community_id=community.slug)
        data = {
            "title": title,
            "page_id": page_id,
            "body_src": "abc def",
            "__action": "edit",
        }
        response = client.post(url, data=data)
        assert response.status_code == 302

        url = url_for(
            "wiki.page_compare",
            rev0="on",
            rev1="on",
            community_id=community.slug,
            title=title,
        )
        response = client.get(url)
        assert response.status_code == 200
