import os
import uuid

import pytest
import tos
from fsspec.tests.abstract import (
    AbstractFixtures,
    AbstractCopyTests,
    AbstractGetTests,
    AbstractPutTests,
)

from tosfsspec import TosFileSystem


def _cleanup_hns_bucket(tos_client, bucket_name):
    try:
        # 1. Abort all multipart uploads
        upload_id_marker = None
        while True:
            output = tos_client.list_multipart_uploads(bucket_name, upload_id_marker=upload_id_marker)
            if output.uploads:
                for upload in output.uploads:
                    tos_client.abort_multipart_upload(bucket_name, upload.key, upload.upload_id)

            if not output.is_truncated:
                break
            upload_id_marker = output.next_upload_id_marker

        # 2. Recursive delete using TOS SDK directly
        def delete_recursive(prefix=''):
            marker = ''
            while True:
                output = tos_client.list_objects(bucket_name, prefix=prefix, delimiter='/', marker=marker)

                # Delete files
                if output.contents:
                    for obj in output.contents:
                        tos_client.delete_object(bucket_name, obj.key)

                # Process subdirectories
                if output.common_prefixes:
                    for cp in output.common_prefixes:
                        # cp.prefix contains the subdirectory path ending with '/'
                        delete_recursive(cp.prefix)
                        # Delete the empty directory itself
                        tos_client.delete_object(bucket_name, cp.prefix)

                if not output.is_truncated:
                    break
                marker = output.next_marker

        delete_recursive()

    except Exception as e:
        print(f"Error cleaning up HNS bucket {bucket_name}: {e}")


class TosFixtures(AbstractFixtures):
    @pytest.fixture(scope="class", params=['hns', 'fns'])
    def fs(self, request):
        bucket_type = request.param
        region = os.environ.get("TOS_REGION")
        endpoint = os.environ.get("TOS_ENDPOINT", "")
        access_key = os.environ.get("TOS_ACCESS_KEY", "")
        secret_key = os.environ.get("TOS_SECRET_KEY", "")

        if not all([region, access_key, secret_key]):
            pytest.skip("TOS environment variables (REGION, ACCESS_KEY, SECRET_KEY) not set")

        fs = TosFileSystem(
            region=region,
            endpoint=endpoint,
            key=access_key,
            secret=secret_key,
        )

        bucket_name = f"test-tos-fs-pytest-src-{bucket_type}-{uuid.uuid4().hex}"
        try:
            fs.mkdir(bucket_name, create_bucket=True, bucket_type=bucket_type)
        except Exception as e:
            pytest.fail(f"Failed to create bucket {bucket_name}: {e}")

        fs._bucket_name = bucket_name
        fs._bucket_type = bucket_type
        makedirs = fs.makedirs

        def patched_makedirs(path: str, exist_ok: bool = True) -> None:
            makedirs(path, exist_ok)

        fs.makedirs = patched_makedirs

        tos_client = tos.TosClientV2(
            ak=access_key,
            sk=secret_key,
            endpoint=endpoint,
            region=region,
        )
        fs._tos_client = tos_client

        yield fs

        try:
            if bucket_type == 'hns':
                _cleanup_hns_bucket(tos_client, bucket_name)
            else:
                upload_id_marker = None
                while True:
                    output = tos_client.list_multipart_uploads(bucket_name, upload_id_marker=upload_id_marker)
                    for upload in output.uploads:
                        tos_client.abort_multipart_upload(bucket_name, upload.key, upload.upload_id)
                    if not output.is_truncated:
                        break
                    upload_id_marker = output.next_upload_id_marker

                files = fs.ls(bucket_name, detail=False)
                for f in files:
                    fs.rm(f, recursive=True)

            fs.rmdir(bucket_name, delete_bucket=True)
        except Exception as e:
            pass

    @pytest.fixture(autouse=True)
    def cleanup_bucket(self, fs):
        yield
        if hasattr(fs, '_bucket_name'):
            bucket_name = fs._bucket_name
            bucket_type = getattr(fs, '_bucket_type', 'fns')

            try:
                if bucket_type == 'hns' and hasattr(fs, '_tos_client'):
                    _cleanup_hns_bucket(fs._tos_client, bucket_name)
                else:
                    files = fs.ls(bucket_name, detail=False)
                    for f in files:
                        fs.rm(f, recursive=True)
            except Exception:
                pass

    @staticmethod
    @pytest.fixture
    def fs_path(fs):
        if hasattr(fs, '_bucket_name'):
            return str(getattr(fs, '_bucket_name'))
        bucket_name = fs.ls("/", detail=False)[0]
        return bucket_name

    @staticmethod
    @pytest.fixture
    def fs_join():
        def join(*parts):
            return "/".join(parts)

        return join

    def supports_empty_directories(self):
        return True


class TestTosCopy(TosFixtures, AbstractCopyTests):
    pass


class TestTosGet(TosFixtures, AbstractGetTests):
    pass


class TestTosPut(TosFixtures, AbstractPutTests):
    pass
