from typing import Optional, List

from src.schemas.app_updates import (
    Versao as VersaoSchema,
    CheckUpdateResponse
)
from src.core.app_updates_storage import (
    get_b2_client,
    get_public_url,
    BUCKET
)


class VersaoService:

    def _scan_versions_from_b2(self) -> List[VersaoSchema]:
        print("Starting _scan_versions_from_b2")
        s3_client = get_b2_client()
        versions = {}
        try:
            paginator = s3_client.get_paginator('list_objects_v2')
            bucket_msg = f"Scanning bucket {BUCKET}"
            print(bucket_msg)
            for page in paginator.paginate(
                    Bucket=BUCKET, Prefix="pomind/"):
                for obj in page.get('Contents', []):
                    key = obj['Key']
                    print(f"Found key: {key}")
                    parts = key.split('/')
                    print(f"Parts: {parts}, len: {len(parts)}")
                    if len(parts) < 3 or not parts[-1].endswith('.exe'):
                        print("Skipped: not exe or len < 3")
                        continue
                    if parts[1] == 'releases':
                        if len(parts) != 4:
                            print("Skipped: releases but len != 4")
                            continue
                        version_str = parts[2]
                        name = parts[3]
                    else:
                        if len(parts) != 3:
                            print("Skipped: not releases and len != 3")
                            continue
                        version_str = parts[1]
                        name = parts[2]
                    print(f"Version str before: {version_str}")
                    if version_str == 'latest':
                        print("Skipped: latest")
                        continue
                    version_str = version_str.lstrip('v')
                    print(f"Version str after: {version_str}")
                    try:
                        major, minor, patch = map(int, version_str.split('.'))
                        build = major * 10000 + minor * 100 + patch
                        print(f"Parsed version: {major}.{minor}.{patch}, "
                              f"build: {build}")
                    except ValueError as e:
                        print(f"Skipped: parse error {e}")
                        continue
                    if version_str not in versions:
                        versions[version_str] = {
                            'build': build,
                            'files': []
                        }
                    versions[version_str]['files'].append({
                        'key': key,
                        'name': name,
                        'size': obj['Size'],
                        'last_modified': obj['LastModified']
                    })
                    print(f"Added to versions: {version_str}")
        except Exception as e:
            print(f"Exception: {e}")
            return []

        print(f"Total versions found: {len(versions)}")
        result = []
        for version_str, data in versions.items():
            if not data['files']:
                continue
            file_info = data['files'][0]
            public_url = get_public_url(file_info['key'])
            versao = VersaoSchema(
                id=data['build'],
                versao=version_str,
                build=data['build'],
                nomeArquivo=file_info['name'],
                caminhoArquivo=public_url,
                hashSha256="",
                tamanhoBytes=file_info['size'],
                changelog="",
                atualizacaoObrigatoria=False,
                ativo=True,
                dataRelease=file_info['last_modified']
            )
            result.append(versao)
        print(f"Returning {len(result)} versions")
        return sorted(result, key=lambda v: v.build, reverse=True)

    async def get_versao(
        self,
            versao_id: int) -> Optional[VersaoSchema]:
        versions = self._scan_versions_from_b2()
        for v in versions:
            if v.id == versao_id:
                return v
        return None

    async def check_for_updates(
        self,
        current_version: Optional[str] = None,
        current_build: Optional[int] = None
    ) -> CheckUpdateResponse:
        """
        Verifica se há atualizações disponíveis.
        Compara com a versão/build atual se fornecidos.
        """
        versions = self._scan_versions_from_b2()
        if not versions:
            return CheckUpdateResponse(
                has_update=False,
                current_version=current_version,
                current_build=current_build,
                latest_version=None,
                latest_build=None,
                update_mandatory=None,
                versao=None
            )

        latest = max(versions, key=lambda v: v.build)

        if current_build is None:
            return CheckUpdateResponse(
                has_update=True,
                current_version=current_version,
                current_build=current_build,
                latest_version=latest.versao,
                latest_build=latest.build,
                update_mandatory=latest.atualizacaoObrigatoria,
                versao=latest
            )

        has_update = latest.build > current_build

        return CheckUpdateResponse(
            has_update=has_update,
            current_version=current_version,
            current_build=current_build,
            latest_version=latest.versao,
            latest_build=latest.build,
            update_mandatory=(
                latest.atualizacaoObrigatoria if has_update else None
            ),
            versao=(
                latest if has_update else None
            )
        )

    async def list_versoes(
        self,
        *,
        ativo: Optional[bool] = None,
        limit: int = 100,
    ) -> List[VersaoSchema]:
        versions = self._scan_versions_from_b2()
        if ativo is not None:
            versions = [v for v in versions if v.ativo == ativo]
        return versions[:limit]

    def list_bucket_contents(self) -> str:
        """Lista o conteúdo do bucket como o comando b2 ls,
        sempre com prefix pomind e recursivo."""
        s3_client = get_b2_client()
        output_lines = []

        output_lines.append(
            "PS C:\\WINDOWS\\System32> "
            f"b2 ls b2://{BUCKET}/pomind/")
        response = s3_client.list_objects_v2(
            Bucket=BUCKET,
            Prefix="pomind/",
            Delimiter='/'
        )
        for common_prefix in response.get('CommonPrefixes', []):
            output_lines.append(common_prefix['Prefix'])
        for obj in response.get('Contents', []):
            output_lines.append(obj['Key'])
        output_lines.append("PS C:\\WINDOWS\\System32>")
        output_lines.append("")

        output_lines.append(
            "PS C:\\WINDOWS\\System32> "
            f"b2 ls b2://{BUCKET}/pomind/releases/ --recursive")
        paginator = s3_client.get_paginator('list_objects_v2')
        for page in paginator.paginate(
            Bucket=BUCKET,
            Prefix="pomind/releases/"
        ):
            for obj in page.get('Contents', []):
                output_lines.append(obj['Key'])
        output_lines.append("PS C:\\WINDOWS\\System32>")

        return "\n".join(output_lines)
