import os
import json

class MultiDB:
    def __init__(self, filename="database.mdb"):
        self.filename = filename
        self.lockfile = filename + ".lock"

        if not os.path.exists(self.filename):
            with open(self.filename, "w", encoding="utf-8") as f:
                f.write("")

    # -----------------------------
    # LOCK SYSTEM
    # -----------------------------
    def _lock(self):
        with open(self.lockfile, "w") as f:
            f.write("locked")

    def _unlock(self):
        if os.path.exists(self.lockfile):
            os.remove(self.lockfile)

    # -----------------------------
    # FILE I/O
    # -----------------------------
    def _read(self):
        with open(self.filename, "r", encoding="utf-8") as f:
            return f.read().splitlines()

    def _write(self, lines):
        with open(self.filename, "w", encoding="utf-8") as f:
            f.write("\n".join(lines))

    # -----------------------------
    # TABLE FINDER
    # -----------------------------
    def _find_table(self, lines, table):
        for i, line in enumerate(lines):
            if line.strip() == f"[TABLE {table}]":
                return i
        return -1

    # -----------------------------
    # RULE SPLITTER
    # -----------------------------
    def _split_rules(self, rule):
        if not rule:
            return []
        rule = rule.replace(" ", "").replace("+", ",").replace("#-", ",#-")
        return [r for r in rule.split(",") if r]

    # -----------------------------
    # CREATE TABLE
    # -----------------------------
    def create_table(self, name, columns):
        self._lock()
        lines = self._read()

        if self._find_table(lines, name) != -1:
            self._unlock()
            raise ValueError("Bu tablo zaten var!")

        col_names = []
        rules = {}

        for col in columns:
            if isinstance(col, dict):
                key = list(col.keys())[0]
                rule = col[key]
                col_names.append(key)
                rules[key] = rule
            else:
                col_names.append(col)
                rules[col] = ""

        lines.append(f"[TABLE {name}]")
        lines.append(json.dumps(col_names, ensure_ascii=False))
        lines.append(json.dumps(rules, ensure_ascii=False))

        self._write(lines)
        self._unlock()

    # -----------------------------
    # VALIDATION
    # -----------------------------
    def _validate(self, value, rule, lines, table_pos, col_index):
        rules = self._split_rules(rule)

        for r in rules:
            if r == "ID":
                continue

            if r == "number":
                if not value.isdigit():
                    return False

            if r == "gmail":
                if not ("@" in value and value.endswith(".com")):
                    return False

            if r == "big":
                if not all(ch.isupper() or ch.isdigit() for ch in value):
                    return False

            if r == "small":
                if not all(ch.islower() or ch.isdigit() for ch in value):
                    return False

            if r == "#-":
                idx = table_pos + 3
                while idx < len(lines) and not lines[idx].startswith("[TABLE"):
                    row = json.loads(lines[idx])
                    if row[col_index] == value:
                        return False
                    idx += 1

        return True

    # -----------------------------
    # GIVE (True/False destekli)
    # -----------------------------
    def give(self, table, values, output_list=None):
        try:
            self._lock()
            lines = self._read()

            tpos = self._find_table(lines, table)
            if tpos == -1:
                raise ValueError("Tablo bulunamadı!")

            col_names = json.loads(lines[tpos + 1])
            rules = json.loads(lines[tpos + 2])

            final_values = []

            # AUTO ID
            if len(values) + 1 == len(col_names) and "ID" in rules.values():
                auto_id = 1
                idx = tpos + 3
                while idx < len(lines) and not lines[idx].startswith("[TABLE"):
                    row = json.loads(lines[idx])
                    auto_id = max(auto_id, int(row[0]) + 1)
                    idx += 1

                final_values.append(str(auto_id))
                final_values.extend(values)

            elif len(values) != len(col_names):
                raise ValueError("Gönderilen veri sayısı yanlış!")

            else:
                final_values = values[:]

            # VALIDATION
            for i, col in enumerate(col_names):
                rule = rules[col]
                if not self._validate(final_values[i], rule, lines, tpos, i):
                    raise ValueError(f"{col} alanı için veri kurala uymuyor: {rule}")

            # Insert row
            lines.insert(tpos + 3, json.dumps(final_values, ensure_ascii=False))
            self._write(lines)
            self._unlock()

            if output_list is not None:
                output_list.append(True)

            return True

        except Exception:
            if output_list is not None:
                output_list.append(False)
                return False
            raise

        finally:
            self._unlock()

    # -----------------------------
    # READ FULL TABLE
    # -----------------------------
    def table_full(self, table):
        lines = self._read()
        tpos = self._find_table(lines, table)
        if tpos == -1:
            raise ValueError("Tablo yok!")

        result = []
        idx = tpos + 3
        while idx < len(lines) and not lines[idx].startswith("[TABLE"):
            result.append(json.loads(lines[idx]))
            idx += 1
        return result

    # -----------------------------
    # CLEAR TABLE (DATA ONLY)
    # -----------------------------
    def clear_full(self, table):
        self._lock()
        lines = self._read()

        tpos = self._find_table(lines, table)
        if tpos == -1:
            self._unlock()
            raise ValueError("Tablo bulunamadı!")

        new_lines = []
        i = 0
        while i < len(lines):
            if i != tpos:
                new_lines.append(lines[i])
                i += 1
                continue

            new_lines.append(lines[i])     
            new_lines.append(lines[i + 1])
            new_lines.append(lines[i + 2])

            j = i + 3
            while j < len(lines) and not lines[j].startswith("[TABLE"):
                j += 1

            i = j

        self._write(new_lines)
        self._unlock()

    # -----------------------------
    # UPDATE TABLE
    # -----------------------------
    def table_update(self, table, columns):
        self._lock()
        lines = self._read()

        tpos = self._find_table(lines, table)
        if tpos == -1:
            self._unlock()
            raise ValueError("Böyle bir tablo yok!")

        col_names = []
        rules = {}
        for col in columns:
            if isinstance(col, dict):
                key = list(col.keys())[0]
                rule = col[key]
                col_names.append(key)
                rules[key] = rule
            else:
                col_names.append(col)
                rules[col] = ""

        data_rows = []
        idx = tpos + 3
        while idx < len(lines) and not lines[idx].startswith("[TABLE"):
            data_rows.append(json.loads(lines[idx]))
            idx += 1

        new_data_rows = []
        old_col_names = json.loads(lines[tpos + 1])

        for row in data_rows:
            new_row = []
            for col in col_names:
                if col in old_col_names:
                    new_row.append(row[old_col_names.index(col)])
                else:
                    new_row.append("")
            new_data_rows.append(new_row)

        new_lines = []
        i = 0
        while i < len(lines):
            if i == tpos:
                new_lines.append(f"[TABLE {table}]")
                new_lines.append(json.dumps(col_names, ensure_ascii=False))
                new_lines.append(json.dumps(rules, ensure_ascii=False))
                for row in new_data_rows:
                    new_lines.append(json.dumps(row, ensure_ascii=False))

                j = tpos + 3
                while j < len(lines) and not lines[j].startswith("[TABLE"):
                    j += 1
                i = j

            else:
                new_lines.append(lines[i])
                i += 1

        self._write(new_lines)
        self._unlock()

    # -----------------------------
    # CONTROL SYSTEM
    # -----------------------------
    def control(self, table, conditions: dict, output_list=None):
        lines = self._read()
        tpos = self._find_table(lines, table)
        if tpos == -1:
            raise ValueError("Tablo bulunamadı!")

        col_names = json.loads(lines[tpos + 1])
        col_indexes = {k: col_names.index(k) for k in conditions}

        found = False
        idx = tpos + 3

        while idx < len(lines) and not lines[idx].startswith("[TABLE"):
            row = json.loads(lines[idx])

            match = True
            for key, val in conditions.items():
                if row[col_indexes[key]] != val:
                    match = False
                    break

            if match:
                found = True
                break

            idx += 1

        if output_list is None:
            print("Var" if found else "Yok")
        else:
            output_list.append(found)

        return found