import os
import subprocess
import sys
import requests
from bs4 import BeautifulSoup
import sqlite3
import schedule
import time
import logging
from transformers import pipeline, BertForQuestionAnswering, BertTokenizer, RobertaForQuestionAnswering, RobertaTokenizer
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from concurrent.futures import ThreadPoolExecutor
import hashlib
import psutil
import torch

def install(package):
    subprocess.check_call([sys.executable, "-m", "pip", "install", package])

required_packages = ['requests', 'beautifulsoup4', 'selenium', 'webdriver-manager', 'transformers', 'psutil', 'torch']
for package in required_packages:
    try:
        __import__(package)
    except ImportError:
        install(package)

logging.basicConfig(level=logging.INFO)

# Wybór urządzenia: CUDA (NVIDIA) lub ROCm (AMD) lub CPU
if torch.cuda.is_available():
    device = torch.device('cuda')
    logging.info("Użycie GPU NVIDIA")
elif torch.backends.mps.is_available():  # Obsługuje ROCm
    device = torch.device('mps')
    logging.info("Użycie GPU AMD")
else:
    device = torch.device('cpu')
    logging.info("Użycie CPU")

# Inicjalizacja modeli
model_qa_1 = BertForQuestionAnswering.from_pretrained("dkleczek/bert-base-polish-uncased-v1").to(device)
tokenizer_qa_1 = BertTokenizer.from_pretrained("dkleczek/bert-base-polish-uncased-v1")

model_qa_2 = RobertaForQuestionAnswering.from_pretrained("deepset/roberta-base-squad2").to(device)
tokenizer_qa_2 = RobertaTokenizer.from_pretrained("deepset/roberta-base-squad2")

qa_pipeline_1 = pipeline("question-answering", model=model_qa_1, tokenizer=tokenizer_qa_1, device=device.index)
qa_pipeline_2 = pipeline("question-answering", model=model_qa_2, tokenizer=tokenizer_qa_2, device=device.index)

chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=chrome_options)

def generate_hash(url):
    return hashlib.md5(url.encode()).hexdigest()

def scrape_dynamic_data(url):
    try:
        driver.get(url)
        time.sleep(3)  # Czekaj na załadowanie strony
        soup = BeautifulSoup(driver.page_source, 'html.parser')
        return soup.get_text()
    except Exception as e:
        logging.error(f"Błąd podczas pobierania danych z {url}: {e}")
        return None

def scrape_data(url):
    cached_data = check_cache(url)
    if cached_data:
        logging.info(f"Pobieranie danych z cache dla: {url}")
        return cached_data
    if "dynamic" in url:
        return scrape_dynamic_data(url)
    else:
        try:
            response = requests.get(url)
            response.raise_for_status()
            soup = BeautifulSoup(response.text, 'html.parser')
            store_cache(url, soup.get_text())
            return soup.get_text()
        except requests.RequestException as e:
            logging.error(f"Błąd podczas pobierania danych z {url}: {e}")
            return None

def store_data(data):
    with sqlite3.connect('knowledge_base.db') as conn:
        c = conn.cursor()
        c.execute('CREATE TABLE IF NOT EXISTS knowledge (content TEXT)')
        c.execute('INSERT INTO knowledge (content) VALUES (?)', (data,))
        conn.commit()

def store_interaction(question, answer):
    with sqlite3.connect('knowledge_base.db') as conn:
        c = conn.cursor()
        c.execute('CREATE TABLE IF NOT EXISTS interactions (question TEXT, answer TEXT)')
        c.execute('INSERT INTO interactions (question, answer) VALUES (?, ?)', (question, answer))
        conn.commit()

def check_cache(url):
    hash_key = generate_hash(url)
    cache_file = f'cache/{hash_key}.txt'
    if os.path.exists(cache_file):
        with open(cache_file, 'r', encoding='utf-8') as file:
            return file.read()
    return None

def store_cache(url, data):
    os.makedirs('cache', exist_ok=True)
    hash_key = generate_hash(url)
    with open(f'cache/{hash_key}.txt', 'w', encoding='utf-8') as file:
        file.write(data)

def gather_data():
    urls = ['https://news.google.com/', 'https://example.com/dynamic']
    with ThreadPoolExecutor(max_workers=4) as executor:
        results = list(executor.map(scrape_data, urls))
        for data in results:
            if data:
                store_data(data)

def learn_from_data():
    with sqlite3.connect('knowledge_base.db') as conn:
        c = conn.cursor()
        c.execute('SELECT content FROM knowledge')
        return [row[0] for row in c.fetchall()]

def monitor_resources():
    cpu_usage = psutil.cpu_percent()
    ram_usage = psutil.virtual_memory().percent
    logging.info(f"Zużycie CPU: {cpu_usage}%, Zużycie RAM: {ram_usage}%")
    if cpu_usage > 85:
        logging.warning("Wykryto wysokie zużycie CPU!")
    if ram_usage > 85:
        logging.warning("Wykryto wysokie zużycie RAM!")

def choose_best_pipeline(question):
    if any(keyword in question.lower() for keyword in ["kiedy", "ile", "co", "gdzie", "dlaczego"]):
        return qa_pipeline_2
    return qa_pipeline_1

def get_location():
    try:
        response = requests.get('https://ipinfo.io')
        data = response.json()
        return data.get('city'), data.get('region'), data.get('country')
    except Exception as e:
        logging.error(f"Błąd podczas uzyskiwania lokalizacji: {e}")
        return None, None, None

def answer_question(question):
    context = " ".join(learn_from_data())
    if not context:
        return "Brak dostępnego kontekstu do udzielenia odpowiedzi."
    pipeline = choose_best_pipeline(question)
    return pipeline(question=question, context=context)['answer']

schedule.every().hour.do(gather_data)
schedule.every(5).minutes.do(monitor_resources)

def run_scheduler():
    while True:
        schedule.run_pending()
        time.sleep(1)

def cleanup():
    driver.quit()  # Upewnij się, że sterownik jest zamknięty

if __name__ == "__main__":
    logging.info("Aplikacja została uruchomiona. Możesz zadawać pytania.")
    try:
        run_scheduler()
        while True:
            user_question = input("Zadaj pytanie (lub 'exit' aby zakończyć): ")
            if user_question.lower() == 'exit':
                break
            answer = answer_question(user_question)
            print(f"Odpowiedź: {answer}")
    finally:
        cleanup()