import os
import time
import json
import re

from collections import defaultdict

from tqdm import tqdm

from .decorators import timer


def create_metadata_entry(entry_type:str, parent, name, stat_info):
    metadata = {
        'type': entry_type,
        'created': stat_info.st_ctime,  # 创建时间戳（可过滤）
        'modified': stat_info.st_mtime,  # 修改时间戳（可过滤）
        'parent': parent,
        'name': name
    }

    if entry_type == 'file':
        metadata['size'] = stat_info.st_size
        metadata['ext'] = os.path.splitext(name)[1].lower()
    elif entry_type == 'folder':
        pass

    return metadata


class MftIndexer:
    def __init__(self,mft_path:str = None):
        self.mft_simulator = defaultdict(dict)
        if mft_path:
            self.import_from_json(mft_path)

    def scan_directory(self,directory_path):
        """扫描目录，同时记录文件和文件夹的元数据"""
        start_time = time.time()
        file_count = 0
        folder_count = 0

        for dir_path, _,filenames in os.walk(directory_path):
            # 处理当前文件夹本身
            try:
                folder_stat = os.stat(dir_path)
                name = os.path.basename(dir_path)
                self.mft_simulator[dir_path] = create_metadata_entry(
                    'folder', os.path.dirname(dir_path), name, folder_stat
                )
                folder_count += 1
            except Exception as e:
                print(f"无法访问 {dir_path}: {e}")
                continue

            for filename in filenames:
                file_path = os.path.join(dir_path, filename)
                try:
                    file_stat = os.stat(file_path)
                    self.mft_simulator[file_path] = create_metadata_entry(
                        'file', dir_path, filename, file_stat
                    )
                    file_count += 1
                except Exception as e:
                    print(f'跳过文件{file_path}: {e}')
                    continue
        end_time = time.time()
        print(f"扫描完成: {file_count} 个文件, {folder_count} 个文件夹")
        print(f"耗时: {end_time - start_time:.2f} 秒")
        return {"file_count": file_count, "folder_count": folder_count, 'duration': end_time - start_time}

    def export_to_json(self,file_path:str):
        directory = os.path.dirname(file_path)
        if not os.path.exists(directory):
            os.makedirs(directory)

        with open(file_path, 'w', encoding='utf-8') as f:
            json.dump(dict(self.mft_simulator), f, ensure_ascii=False, indent=4)
        print(f"已导出至文件: {file_path}")

    @timer
    def import_from_json(self,file_path:str):
        with open(file_path,'r',encoding = 'utf-8') as f:
            self.mft_simulator = json.load(f)

class InvertedIndex:
    def __init__(self):
        self.id_to_path = {}
        self.path_to_id = {}
        self.inverted_index = defaultdict(set)  #倒排索引结构
        self.tokenizer = re.compile(r"""
            [\u4e00-\u9fa5]                     # 中文字符
            |
            [a-zA-Z]+(?:[-'][a-zA-Z]+)*        # 英文单词（支持连字符和缩写）
            |
            \d+\.?\d*                          # 数字（整数或小数）
        """, re.VERBOSE)
        self.counter = 0

    @timer
    def build_index(self, file_index):
        """构建倒排索引"""
        for path, meta in tqdm(file_index.items(), desc='Build index'):
            if path not in self.path_to_id:
                self.path_to_id[path] = self.counter
                self.id_to_path[self.counter] = path
            filename = os.path.basename(path)

            tokens = self.tokenizer.findall(filename.lower())
            # print(meta['parent_dir'])
            for token in tokens:
                self.inverted_index[token].add(self.counter)
            self.counter += 1

    @timer
    def search(self, query):
        """基础搜索实现"""
        tokens = self.tokenizer.findall(query.lower())
        if not tokens:
            return []

        # 计算文档交集（位图优化版）
        result = None
        for token in tokens:
            docs = self.inverted_index.get(token, set())
            if result is None:
                result = docs
            else:
                result = result.intersection(docs)

        return list(result) if result else []