from __init__ import *
from functions.functions import *
import re

def slugify(text):
    text = text.lower()
    return re.sub(r'[\W_]+', '_', text)

class Serializer(object):
    def __init__(self, data):
        self.data = data
        self.list = list()
        
    def one(self):
        x = self.data.__dict__
        del x['_sa_instance_state']
        self.list.append(x)
        return self.list
    
    def many(self):
        for x in self.data:
            x = x.__dict__
            del x['_sa_instance_state']
            self.list.append(x)
        return self.list
        
def normalize_kenyan_phone(phone: str) -> str | None:
    """
    Converts a phone number into a valid Kenyan format: 2547XXXXXXXX.
    
    Accepted input formats:
    - 07XXXXXXXX
    - 7XXXXXXXX
    - +2547XXXXXXXX
    - 2547XXXXXXXX
    - 011XXXXXXXX (Safaricom VoLTE)
    
    Returns:
        A string like '2547XXXXXXXX' or None if invalid.
    """
    phone = phone.strip().replace(" ", "").replace("-", "")
    
    # Remove + if present
    if phone.startswith("+"):
        phone = phone[1:]

    # Match valid Kenyan mobile numbers
    if re.fullmatch(r"2547\d{8}", phone) or re.fullmatch(r"2541\d{8}", phone):
        return phone
    elif re.fullmatch(r"07\d{8}", phone):
        return "254" + phone[1:]
    elif re.fullmatch(r"7\d{8}", phone):
        return "254" + phone
    elif re.fullmatch(r"1\d{8}", phone):  # Safaricom VoLTE numbers
        return "254" + phone
    elif re.fullmatch(r"011\d{7}", phone):
        return "254" + phone[1:]
    
    return None
        
        
class ContactUsRequest(Resource):
    def __init__(self):
        self.values = request.args or request.json or request.form
        
    def post(self):
        new = Enquiry(
            nature_of_enquiry = self.values.get("nature_of_enquiry"),
            firstname = self.values.get("firstname"),
            surname = self.values.get("surname"),
            email = self.values.get("email"),
            phone = self.values.get("phone"),
            message = self.values.get("message"),
        )
        db.session.add(new)
        db.session.commit()
        return jsonify(dict(message='Enquiry sent to admin', success=True))
        
class SellYourCar(Resource):
    def __init__(self):
        self.values = request.args or request.json or request.form
        
    def post(self):
        new = CarInfo(
            title = self.values.get('title'),
            firstname = self.values.get('firstname'),
            surname = self.values.get('surname'),
            email = self.values.get('email'),
            phone = self.values.get('phone'),
            make = self.values.get('make'),
            model = self.values.get('model'),
            year = self.values.get('year'),
            reg_number = self.values.get('regNumber'),
            mileage = self.values.get('mileage'),
            comments = self.values.get('comments'),
        )
        db.session.add(new)
        db.session.commit()
        
        return jsonify(dict(message='Data sent to admin', success=True))
    
class SearchAPI(Resource):
    def get(self):
        this_year = int(datetime.now().year)
        years = list(range(1995, this_year+1))
        
        make = [dict(name=select.name, slug = select.slug, value = select.id) for select in CarMake.query.all()]
        year = [dict(name=year, value = year) for year in years[::-1]]
        condition = [dict(name=select.name, value = select.id) for select in Condition.query.all()]
        body_type = [dict(name=select.name, value = select.id) for select in BodyTypes.query.all()]
        prices = [
            dict(value= 5000000, name = "Kshs 5,000,000"),
            dict(value= 10000000, name = "Kshs 10,000,000"),
            dict(value= 20000000, name = "Kshs 20,000,000"),
            dict(value= 25000000, name = "Kshs 25,000,000"),
            dict(value= 30000000, name = "Kshs 30,000,000"),
            dict(value= 50000000, name = "Kshs 50,000,000"),
            ]
        return make_response(jsonify(dict(
            makes = make, 
            years = year, 
            max_prices = prices,
            conditions = condition,
            body_types = body_type)))
    def patch(self):
        self.make_id = request.json.get('make_id')
        models = [dict(value = select.id, slug=select.slug, name = select.name) for select in CarModel.query.filter(CarModel.make_id == self.make_id).all()]
        return make_response(jsonify(dict(models = models)))
    
    def post(self):
        self.condition = request.json.get('condition', None)
        self.body_type = request.json.get('body_type', None)
        self.make = request.json.get('make', None)
        self.max_price = request.json.get('max_price', None)
        self.model = request.json.get('model', None)
        self.year = request.json.get('year', None)
        
        vehicles = Listing.query.join(CarModel).join(CarMake)
        if self.condition:
            vehicles = vehicles.filter(Listing.condition==self.condition)
        if self.body_type:
            vehicles = vehicles.filter(Listing.body_type==self.body_type)
        if self.make:
            vehicles = vehicles.filter(or_(Listing.make==self.make, CarMake.slug==self.make))
        if self.max_price:
            vehicles = vehicles.filter(Listing.price <= self.max_price)
        if self.model:
            vehicles = vehicles.filter(or_(Listing.model==self.model, CarModel.slug == self.model))
        if self.year:
            vehicles = vehicles.filter(Listing.year==self.year)
            
        count = vehicles.count()
        
        vehicles = vehicles.order_by(Listing.id.desc()).all()
        items_list = list()
        
        for vehicle in vehicles:
            items_list.append(dict(
                
                id =  vehicle.id,slug = vehicle.slug,title = vehicle.title, VIN = vehicle.VIN, price = vehicle.price,
                mileage = vehicle.mileage, year = vehicle.year, engine_size = vehicle.engine_size,
                model = vehicle.model2.name, make = vehicle.model2.car_make.name,
                condition = vehicle.condition2.name, body_type = vehicle.body_type2.name,
                drive_type = vehicle.drive_type2.name, transmission = vehicle.transmission2.name,
                fuel_type = vehicle.fuel_type2.name, color = vehicle.color2.name,
                doors = vehicle.doors2.name, cylinders = vehicle.cylinders2.name,
                images = f'{request.url_root}static/files/{vehicle.images[0]}',
                status = vehicle.status2.name,
            ))
        return make_response(jsonify(dict(message='Request successful', 
                                          success=True, vehicles = items_list, 
                                          count = count)))
class SingleVehicle(Resource):
    def __init__(self):
        self.values = request.args or request.values or request.form or request.json
        self.vehicle_id = self.values.get('vehicle_id')
        self.slug = self.values.get('slug')
    def featurePicker(self, features):
        fs = []
        for feature_id in features:
            feature = Features.query.filter_by(id = feature_id).first()
            if feature:
                fs.append(feature.name)
        return fs
    def imagePicker(self, images):
        imgs = []
        if len(images) > 0:
            for image in images:
                if image:
                    imgs.append(f'{request.url_root}static/files/{image}')
        return imgs
    def imagePicker1(self, images):
        image = ''
        if len(images) > 0:
            image = f'{request.url_root}static/files/{images[0]}'
        return image
    def create_youtube_link(self, video_id):
        """
        Generates a YouTube link given a video ID.

        Args:
            video_id (str): The unique identifier of the YouTube video.

        Returns:
            str: A full YouTube URL corresponding to the given video ID.
        """
        link = None
        if video_id:
            base_url = "https://www.youtube.com/watch?v="
            link = base_url + video_id
        return link
               
    def get(self):
        vehicle = Listing.query.filter(or_(Listing.id==self.vehicle_id, Listing.slug == self.slug)).first()
        if vehicle:
            features = self.featurePicker(vehicle.features)
            
            car = dict(
                id =  vehicle.id, slug = vehicle.slug, title =  vehicle.title, VIN =  vehicle.VIN, price =  vehicle.price,
                mileage =  vehicle.mileage, year =  vehicle.year, engine_size =  vehicle.engine_size,
                model =  vehicle.model2.name, make =  vehicle.model2.car_make.name,
                condition =  vehicle.condition2.name, body_type =  vehicle.body_type2.name,
                drive_type =  vehicle.drive_type2.name, transmission =  vehicle.transmission2.name,
                fuel_type =  vehicle.fuel_type2.name, color =  vehicle.color2.name,
                doors =  vehicle.doors2.name, cylinders =  vehicle.cylinders2.name,
                status = vehicle.status2.name,
                staff = dict(
                    name =  f"{vehicle.staff.first_name} {vehicle.staff.last_name}",
                    email = vehicle.staff.email, phone_number = normalize_kenyan_phone(vehicle.staff.phone_number),
                ),
                tags_or_keyword =  vehicle.tags_or_keyword,
                youtube =  self.create_youtube_link(vehicle.youtube),
                description =  vehicle.description, terms_of_services =  vehicle.terms_of_services,
                features =  features, images = self.imagePicker(vehicle.images)
            )
            related = self.RelatedCars(vehicle.make)
            return make_response(jsonify(dict(vehicle = car, related = related)))
        else:
            return make_response(jsonify(
                dict(
                    message = "Vehicle not found",
                    success = False
                )
            ))
    
    def RelatedCars(self, vehicle_make):
        vehicles = Listing.query.filter(Listing.active==True,
                    Listing.make == vehicle_make,
                    Listing.id != self.vehicle_id).order_by(
                        Listing.id.desc()).limit(8).all()
        items_list = list()
        for vehicle in vehicles:
            items_list.append(dict(
                id =  vehicle.id, slug = vehicle.slug, title =  vehicle.title, VIN =  vehicle.VIN, price =  vehicle.price,
                mileage =  vehicle.mileage, year =  vehicle.year, engine_size =  vehicle.engine_size,
                model =  vehicle.model2.name, make =  vehicle.model2.car_make.name,
                condition =  vehicle.condition2.name, body_type =  vehicle.body_type2.name,
                drive_type =  vehicle.drive_type2.name, transmission =  vehicle.transmission2.name,
                fuel_type =  vehicle.fuel_type2.name, color =  vehicle.color2.name,
                doors =  vehicle.doors2.name, cylinders =  vehicle.cylinders2.name,
                status = vehicle.status2.name,
                images = self.imagePicker1(vehicle.images)
            ))
        return items_list
    def post(self):
        try:
            new = RequestModel(
                vehicle_id = self.values.get("vehicle_id"), name = self.values.get("name"),
                phone = self.values.get("phone"), email = self.values.get("email"),
                subject = self.values.get("subject"), message = self.values.get("message"),
            )
            db.session.add(new)
            db.session.commit()
            return make_response(jsonify(dict(message = 'Request sent successfully', success = True)))
        except Exception as e:
            return make_response(jsonify(dict(message = f"{str(e)}", success = False)), 400)

class HomePageVehicles(Resource):
    def get(self):
        vehicles = Listing.query.all()
        print(vehicles)
        return make_response(jsonify())
    
class ReviewsAPI(Resource):
    def get(self):
        reviews = Review.query.filter_by(active=True).order_by(Review.rating.desc()).limit(3).all()
        items_list = list()
        for review in reviews:
            items_list.append(dict(
                customer_name = review.customer_name ,
                rating = review.rating ,
                comment = review.comment
            ))
        return make_response(jsonify(dict(message='Request Success', 
                                          success=True,
                                          reviews=items_list)))
class BlogArticle(Resource):
    def __init__(self):
        self.data = request.args or request.values or request.form or request.json 
    def get(self):
        self.article_id = self.data.get('article_id', None)
        self.slug = self.data.get('slug', None)
        
        if self.article_id or self.slug:
            article = BlogArticles.query.filter(or_(BlogArticles.id == self.article_id, 
                                                    BlogArticles.slug == self.slug)).first()
            
            article2 = dict(slug = article.slug, title = article.title,
                author_id = article.author_id, viewed = article.viewed,
                likes = article.likes, date = article.date, article = article.article,
                comments_count = len(article.comments), id = article.id,
                image = f'{request.url_root}static/files/{article.image}'
            )
            return make_response(jsonify(dict(
                article=article2,
                comments = [
                    dict(
                        id = comment.id,
                        content = comment.content,
                        name = comment.name,
                        date = comment.date,
                    )
                    for comment in article.comments],
                message='Request Success', 
                success=True)))
            
        return make_response(jsonify(dict(message='Request Error!, Article ID or slug required', 
                                        success=False)))
    def post(self):
        try:
            new = Comment(
                post_id = self.data.get('article_id'),
                name = self.data.get('name'),
                email = self.data.get('email'),
                content = self.data.get('comment')
            )
            db.session.add(new)
            db.session.commit()
            return make_response(jsonify(dict(message='Comment posted successfully', success=True)))
        except Exception as e:
            return make_response(jsonify(dict(message=f'{str(e)}', success=False)))
class NewsAPI(Resource):
    def get(self):
        # Extract pagination parameters (default to page 1, 10 items per page)
        page = request.args.get('page', 1, type=int)
        limit = request.args.get('limit', 15, type=int)

        # Use SQLAlchemy's built-in paginate method
        pagination = BlogArticles.query.filter_by(active=True)\
            .order_by(BlogArticles.id.desc())\
            .paginate(page=page, per_page=limit, error_out=False)

        # Extract the actual items for the current page
        newsArticles = pagination.items

        items_list = []
        for newsArticle in newsArticles:
            items_list.append({
                'id': newsArticle.id,
                'slug': newsArticle.slug,
                'title': newsArticle.title,
                'author_id': newsArticle.author_id,
                'viewed': newsArticle.viewed,
                'likes': newsArticle.likes,
                'date': newsArticle.date,
                'comments': len(newsArticle.comments),
                'image': f'{request.url_root}static/files/{newsArticle.image}'
            })

        # Return the items along with the pagination metadata
        return make_response(jsonify({
            'message': 'Request Success',
            'success': True,
            'newsArticles': items_list,
            'pagination': {
                'total_items': pagination.total,       # Total number of active articles in DB
                'total_pages': pagination.pages,       # Total number of pages
                'current_page': pagination.page,       # Current page number
                'per_page': pagination.per_page,       # Number of items per page (limit)
                'has_next': pagination.has_next,       # Boolean: Is there a next page?
                'has_prev': pagination.has_prev        # Boolean: Is there a previous page?
            }
        }))

class ContactUsAPI(Resource):
    def get(self):
        contact = ContactUs.query.filter(ContactUs.active==True).first()
        if contact:
            cons = dict(content=contact.message, success = True)
        else:
            cons = dict(content='', success = False)
        return make_response(jsonify(cons))
        
class AboutUsAPI(Resource):
    def get(self):
        about = AboutUs.query.filter(AboutUs.active==True).first()
        abts = {}
        if about:
            abts = dict(content=about.message, success = True)
        else:
            abts = dict(content='', success = False)
        return make_response(jsonify(abts))
class HomeListingStatusAPI(Resource):
    def get(self):
        statuses = CarStatus.query.filter(CarStatus.active == True).all()
        sts = []
        for status in statuses:
            sts.append(dict(id = status.id, name = status.name, description = status.description))
        return make_response(jsonify(sts))
class HomeListingAPI(Resource):
    def __init__(self):
        self.data = request.args or request.values or request.form or request.json
        self.limit = int(self.data.get('limit', 20))
        self.page = int(self.data.get('page', 1))
        self.featured = self.data.get('featured', None)
        self.status = self.data.get('status', None)
        
    def imagePicker(self, images):
        image = ''
        if len(images) > 0:
            image = f'{request.url_root}static/files/{images[0]}'
        return image
        
    def get(self):
        vehicles = Listing.query.filter_by(active=True).order_by(Listing.id.desc())
        
        if self.featured:
            vehicles = vehicles.filter_by(featured=True)
        if self.status:
            vehicles = vehicles.filter_by(status=self.status)
            
        # vehicles = vehicles.all()
        vehiclesList = vehicles.paginate(page = self.page,per_page = self.limit,error_out=False)
        vehicles = vehiclesList.items
        items_list = list()
        for vehicle in vehicles:
            staff = dict(
                name =  f"{vehicle.staff.first_name} {vehicle.staff.last_name}",
                email = vehicle.staff.email, phone_number = normalize_kenyan_phone(vehicle.staff.phone_number),
            )
            items_list.append(dict(
                id =  vehicle.id, slug = vehicle.slug, title =  vehicle.title, VIN =  vehicle.VIN, price =  vehicle.price,
                mileage =  vehicle.mileage, year =  vehicle.year, engine_size =  vehicle.engine_size,
                model =  vehicle.model2.name, make =  vehicle.model2.car_make.name,
                condition =  vehicle.condition2.name, body_type =  vehicle.body_type2.name,
                drive_type =  vehicle.drive_type2.name, transmission =  vehicle.transmission2.name,
                fuel_type =  vehicle.fuel_type2.name, color =  vehicle.color2.name,
                doors =  vehicle.doors2.name, cylinders =  vehicle.cylinders2.name, staff = staff,
                status = vehicle.status2.name, images = self.imagePicker(vehicle.images), 
            ))
        return make_response(
            jsonify(
                dict(
                    message='Request Success', 
                    success = True, 
                    cars = items_list,
                    pagination = dict(
                        total_items = vehiclesList.total,
                        total_pages = vehiclesList.pages,
                        current_page = vehiclesList.page,
                        has_next = vehiclesList.has_next,
                        has_prev = vehiclesList.has_prev,
                        next_page = vehiclesList.next_num if vehiclesList.has_next else None,
                        previous_page = vehiclesList.prev_num if vehiclesList.has_prev else None,
                        items_per_page = vehiclesList.per_page,
                        last_page = vehiclesList.pages,
                        first_page = 1,
                    )
                    )
                )
            )
class BrandsAPI(Resource):
    def get(self):
        brands = CarMake.query.filter_by(active=True).all()
        items_list = list()
        for brand in brands:
            items_list.append(dict(
                description = brand.description,
                slug = brand.slug,
                count = self.carsCount(brand.models),
                name = brand.name,
                id = brand.id,
                logo = f'{request.url_root}static/files/{brand.logo}'
            ))
        return make_response(jsonify(dict(message='Request Success', 
                                          success=True,
                                          brands=items_list)))
        
    def carsCount(self, brand_models):
        count = 0
        for brand in brand_models:
            count += len(brand.cars)
        return count
    
class SliderAPI(Resource):
    def create_youtube_link(self, video_id):
        """
        Generates a YouTube link given a video ID.

        Args:
            video_id (str): The unique identifier of the YouTube video.

        Returns:
            str: A full YouTube URL corresponding to the given video ID.
        """
        link = None
        if video_id:
            base_url = "https://www.youtube.com/watch?v="
            link = base_url + video_id
        return link
    
    def get(self):
        sliders = SliderModel.query.filter_by(active=True).all()
        items_list = list()
        for slider in sliders:
            items_list.append(dict(
                image = f'{request.url_root}static/files/{slider.image}',
                link = slider.link,
                youtube_video_id =  self.create_youtube_link(slider.youtube),
                message = slider.message,
            ))
        return make_response(jsonify(dict(message='Request Success', 
                                          success=True,
                                          sliders=items_list)))
    
class UsersApi(Resource):
    @jwt_required()
    def get(self):
        current_user = get_jwt_identity()
        # print(current_user)  
        users = Users.query.all()
        userList = Serializer(users).many()
        for user in userList : del user['password'] 
        return make_response(jsonify(userList))
    
    @jwt_required()
    def post(self):
        data = request.args or request.form or request.values or request.json
        print(data)
        return make_response(jsonify(data))
    
    @jwt_required()
    def put(self):
        page = request.args or request.form or request.values or request.json
        return make_response(jsonify(page))
    
    @jwt_required()
    def patch(self):
        page = request.args or request.form or request.values or request.json
        return make_response(jsonify(page))
    
    @jwt_required()
    def delete(self):
        page = request.args or request.form or request.values or request.json
        return make_response(jsonify(page))
    
class Auth(Resource):
    def get(self):
        print(self)
        return make_response(jsonify(dict(name='Tony', token='secret')))
